2009-05-22 3 views
100

Welches ist effizienter über einen sehr großen Satz von Dateien und sollte verwendet werden?find -exec cmd {} + vs | xargs

find . -exec cmd {} + 

oder

find . | xargs cmd 

(Angenommen, es gibt in den Dateinamen sind keine lustigen Charaktere)

+0

Verwandte: https://stackoverflow.com/questions/9612090/how-to-loop-through-file-names-returned-by-find –

Antwort

94

Geschwindigkeitsunterschied wird unbedeutend sein.

Aber Sie müssen sicherstellen, dass:

  1. Ihr Skript wird nicht davon ausgehen, dass keine Dateibereich haben wird, Tab, etc in Dateinamen; die erste Version ist sicher, die zweite ist nicht.

  2. Ihr Skript behandelt keine Datei, die mit "-" als Option beginnt.

So sollte der Code wie folgt aussehen:

find . -exec cmd -option1 -option2 -- {} + 

oder

find . -print0 | xargs -0 cmd -option1 -option2 -- 

Die erste Version ist kürzer und einfacher zu schreiben, wie Sie 1 ignorieren können, aber die zweite Version ist portabler und sicherer, da "-exec cmd {} +" eine relativ neue Option in GNU findutils ist (seit 2005, viele laufende Systeme werden es noch nicht haben) und es war buggy recently. Auch viele Leute kennen das nicht "-exec cmd {} +", wie Sie aus anderen Antworten sehen können.

+4

-print0 ist auch eine GNU find (und GNU xargs) -Option, die fehlt von vielen Nicht-Linux-Systemen, daher ist das Portabilitätsargument nicht so gültig.Mit Just-print und dem Verlassen der Xargs ist * jedoch sehr portabel. – dannysauer

+4

Der Punkt ist, dass ohne -print0 es nicht funktioniert, wenn es eine Datei mit einem Leerzeichen oder einer Registerkarte usw. gibt. Dies kann eine Sicherheitslücke sein, als ob es einen Dateinamen wie "foo -o index.html" gäbe als eine Option behandelt. Versuchen Sie es in einem leeren Verzeichnis: "touch - foo \ -o \ index.html; find. | Xargs cat". Sie erhalten: "cat: invalid option - 'o'" – Tometzky

+2

Sein Beispiel ist ein Dateiname, der ein - enthält. Ohne -print0 spuckt find ./foo -o index.html aus. Also vielleicht mit einem - ist keine große Sache, aber das Ergebnis ist wenig verändert, und auf einem Mehrbenutzer-System, könnte einen Angriffsvektor zur Verfügung stellen, wenn Ihr Skript weltweit lesbar ist. – bobpaul

7
find . | xargs cmd 

effizienter ist (es läuft cmd so wenig wie möglich, im Gegensatz zu exec, die cmd einmal für jedes Spiel läuft). Sie werden jedoch in Schwierigkeiten geraten, wenn Dateinamen Leerzeichen oder funky Zeichen enthalten.

Im folgenden wird vorgeschlagen, verwendet werden:

find . -print0 | xargs -0 cmd 

dies funktionieren wird, auch wenn die Dateinamen flippige Zeichen (-print0find Druck NUL-termini Matches macht, -0xargs dieses Format erwarten macht.)

+25

Dies ist nicht "finden. -exec cmd {} \;" aber "finden. -exec cmd {} +". Letzteres wird nicht eine Datei gleichzeitig ausführen. – Tometzky

+2

Beachten Sie, dass der 'xargs' Ansatz tatsächlich wesentlich langsamer ist, wenn es keine (oder nur wenige) übereinstimmende Dateien gibt und' cmd' nicht viel für jede Datei zu tun hat. Wenn Sie zum Beispiel in einem leeren Verzeichnis arbeiten, dauert die 'xargs'-Version mindestens doppelt so lange, da zwei Prozesse gestartet werden müssen und nicht nur eine. (Ja, der Unterschied ist normalerweise nicht wahrnehmbar bei * nix, aber in einer Schleife könnte es wichtig sein; oder, versuchen Sie es unter Windows irgendwann ...) – SamB