Was bedeutet "{} \;" in einem Linux-Befehl?

37

Manchmal sehe ich den folgenden Befehl:

find . -name  * -exec ls -a {} \;

Ich wurde gebeten, dies auszuführen.

Was {} \;heißt hier?

codeofnode
quelle
1
-name *ist überflüssig.
Kevin
3
Schauen Sie sich auch die Erläuterungen für andere Arten von Fragen wie diese an. Hier ist die Ausgabe für Ihren Befehl. .
Glutanimate
8
-name *ist schlimmer als überflüssig. Da das *nicht in Anführungszeichen gesetzt ist, erweitert die Shell es auf die Liste der Dateinamen im aktuellen Ordner, wobei Leerzeichen falsch behandelt werden, was zu unerwarteten Ergebnissen oder einer Fehlermeldung führt. Als zusätzlichen Punkt findhat viele Funktionen, von denen eine darin besteht, Dateien aufzulisten; Dies vermeidet die Verwendung -exec. ZB können Sie find . -printoder verwenden find . -ls. Schließlich gibt es zwei Möglichkeiten , die Semikolons zu entkommen: entweder , wie Sie mit dem Backslash haben, \;oder mit einem Zitat: ';'. Verwenden Sie, womit Sie sich wohler fühlen.
Paddy Landau

Antworten:

48

Wenn Sie laufen findmit exec, {}erweitert auf die Dateinamen jede Datei oder das Verzeichnis gefunden mit find(so dass lsin Ihrem Beispiel jeden gefundenen Dateinamen als Argument bekommt - zur Kenntnis , dass es nennt lsoder was auch immer anderer Befehl , den Sie angeben , einmal für jede Datei gefunden).

Semikolon ;beendet den Befehl, der von ausgeführt wird exec. Es muss mit einem Escapezeichen versehen werden, \damit die Shell, die Sie ausführen, findes nicht als ihren eigenen besonderen Charakter behandelt, sondern es an weitergibt find.

In diesem Artikel finden Sie weitere Informationen.


Außerdem findbietet einige Optimierungen mit exec cmd {} +- wenn so läuft, findAppends Dateien an das Ende des Befehls gefunden , anstatt sie einmal pro Datei aufgerufen wird (so dass der Befehl nur einmal ausgeführt wird, wenn möglich).

Der Unterschied im Verhalten (wenn nicht in der Effizienz) ist leicht erkennbar, wenn mit lsz

find ~ -iname '*.jpg' -exec ls {} \;
# vs
find ~ -iname '*.jpg' -exec ls {} +

Angenommen, Sie haben einige jpgDateien (mit ausreichend kurzen Pfaden ), ist das Ergebnis eine Zeile pro Datei im ersten Fall und das Standardverhalten lsbei der Anzeige von Dateien in Spalten für letztere.

moon.musick
quelle
1
Ich denke , es wäre von Vorteil für Sie , um den Kontrast \;mit +.
Kevin
Wie unterscheidet es sich von find . -name * | ls -a -?
András Hummer
@DrH Es geht nicht darum, Shell die Platzhaltererweiterung durchführen zu lassen, sondern den Platzhalterausdruck an weiterzuleiten find. Außerdem lshängt die Ausgabe von in diesem Fall anscheinend nicht von der Eingabe ab - egal, was ich als Filter verwende find, es wird lsnur der Inhalt des Arbeitsverzeichnisses angezeigt, und das ist alles. Überprüfen Sie zum Beispiel find ~ -iname '*.jpg' -exec ls -a {} \;vs find ~ -iname '*.jpg' | ls -a.
moon.musick
@ DrH oder sogar echo 'foo' | ls -a.
moon.musick
@ moon.musick, ich glaube, Sie haben das Wichtige -in Ihrem ls -a -Befehl verpasst, als Sie getestet haben, was @ dr-h abgefragt hat.
Daniel Llewellyn
20

Von der Manpage für den findBefehlManpage-Symbol :

-exec command ;
              Execute  command;  true if 0 status is returned.  All following arguments to find are taken to be arguments to
              the command until an argument consisting of `;' is encountered.  The string `{}' is replaced  by  the  current
              file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it
              is alone, as in some versions of find.  Both of these constructions might need to be escaped (with a  `\')  or
              quoted  to  protect them from expansion by the shell.

Also hier ist die Erklärung:

{}bedeutet "die Ausgabe von find". Wie in "was findauch immer gefunden". findgibt den Pfad der gesuchten Datei zurück, oder? So {}ersetzt es; Es ist ein Platzhalter für jede Datei, die der findBefehl findet (von hier genommen ).

Der \;Teil sagt im Grunde find"okay, ich bin fertig mit dem Befehl, den ich ausführen wollte".

Beispiel:

Nehmen wir an, ich befinde mich in einem Verzeichnis voller .txtDateien. Ich laufe dann:

find . -name  '*.txt' -exec cat {} \;

Der erste Teil find . -name *.txtgibt eine Liste der .txtDateien zurück. Der zweite Teil, -exec cat {} \;wird den catAusführungsbefehl für jede durch gefundene Datei find, so cat file1.txt, cat file2.txtund so weiter.

Alaa Ali
quelle
4
Das Teil *.txtmuss mit angegeben werden '*.txt'. Dies liegt daran, dass, wenn sich .txtDateien im aktuellen Ordner befinden, die Shell dies erweitert und Sie falsche Ergebnisse oder eine Fehlermeldung erhalten. find -name '*.txt' -exec cat {} \;
Paddy Landau
@ Alaa Ali sehr gut erklärt
Pushya