Michael Bischof <[EMAIL PROTECTED]> wrote:

> Am Samstag, 10. September 2005 16:22 schrieb Tobias C. Rittweiler:
>
> > Michael Bischof <[EMAIL PROTECTED]> wrote:
> >
> > > Und ein weiteres Problem:
> > > [EMAIL PROTECTED] cur]# rm `grep -l '[...]' *`
> > > -bash: /bin/grep: Argument list too long
> > > rm: zu wenige Argumente
> > > »rm --help« gibt weitere Informationen.
> >
> > man xargs
>
> Gut, und was heißt das jetzt ? Dort steht nicht was in o.g. Befehl falsch 
> oder 
> zu lang ist. Bzw. ich verstehe wohl nicht wie man mit Hilfe von xargs einen 
> richtigen Befehl zusammen bauen könnte.

Das Problem ist, dass der `*' Wildcat in deinem `grep' Befehlsausdruck
zu mehr Dateien expandiert als eine Konstante (MAX_ARGS_PAGES) im Kernel
dafuer standardmäßig reserviert. 

Anstatt alle Dateien in dem aktuellen Verzeichnis von deiner Shell
aufeinmal expandieren zu lassen und dem `grep' Befehl zu übergeben,
musst du ihm eine Datei nach der anderen (bzw. stets nur soviele, dass
obige Konstante nicht überschritten wird) zuspielen. Dafür kann man
`xargs' verwenden, denn dieser Befehl liest von der Standardeingabe
(stdin) die Dateien, die es dem Befehlsausdruck übergibt, den du xargs
wiederum mitgibst.

  mkdir /tmp/xargs-beispiel && cd /tmp/xargs-beispiel

  echo foo1 > foo1 ; echo foo2 > foo2 ; echo foo3 > foo3
  echo bar1 > bar1 ; echo bar2 > bar2 ; echo bar3 > bar3

Wir haben jetzt 6 Dateien foo{1,2,3} und bar{1,2,3}, in denen jeweils
ihr Name steht. Haben wir nun noch eine Datei, in der wiederum jeder
Name dieser Dateien steht:

  echo foo{1,2,3} bar{1,2,3} > dateien-liste

Nun kann man mit `xargs' aus dieser Datei jeden der Namen lesen und
einen Befehl jeweils darauf ausführen lassen:

  cat dateien-liste | xargs grep -l foo  

bzw. äquivalent dazu: 

    xargs grep -l foo < dateien-liste

Dabei sollte `foo1', `foo2' und `foo3' wiedergegeben werden, denn dies
sind ja die drei Dateien, die die Zeichenkette "foo" enthalten.

Natürlich ist es relativ umständlich immer erst eine Datei zu erstellen,
die eine Liste der Dateinamen enthält. Aber dafür gibt es in Unix ja
Pipes:

  find . -type f -print0 | xargs -0 grep -l foo

  (`-print0' und `-0' sind dafür verantwortlich auch den Fall richtig
  abzuhandeln, wenn die Dateinamen Leerzeichen oder Neuline-Zeichen
  enthalten.)

Um die Dateien schließlich noch zu löschen, hängst du einfach nochmal
ein `xargs' daran:

  find . -type f -print0 | xargs -0 grep -Z -l foo | xargs -0 rm

  (`-Z' ist das Pendant in `grep' zu `-print0' in `find' und zu `-0' in
  `xargs'. Wenn dir das irgendwie wie unnötig viel Ballast vorkommt, nur
  um Dateinamen mit Leer- und Newline-Zeichen zu unterstützen,
  willkommen in der doch manchmal sehr gehirnamputierten Welt von Unix.)

Alternativ könnte man sich auch die `-exec' Option von `find' wie folgt
zu Nutze machen:

  find . -type f -exec grep -q foo '{}' \; -print 0 | xargs -0 rm


Bemerke jedoch den Unterschied von beiden Varianten zu deiner Version:
Da nirgendswo ein Wildcat verwendet wird, kann auch nie die maximale
Anzahl an Argumenten überschritten werden -- denn es wird `grep' jeweils
nur jeder Dateiname einzeln übergeben. (Dies ist natürlich auch ein
Nachteil, denn anstatt alle auf einmal zu pruefen, wird jetzt für jede
Datei ein eigener `grep' und `rm' Befehl gestartet.  Dieses Verhalten
könnte man aber wohl mit der `--max-args' Option von `xargs' verändern.)


-t


--
----------------------------------------------------------------------------
PUG - Penguin User Group Wiesbaden - http://www.pug.org

Antwort per Email an