Grundlegendes zur Option -exec von find (1) (geschweifte Klammern und Pluszeichen)

17

Könnte jemand mit dem folgenden Befehl erklären, wozu die letzten geschweiften Klammern ({}) und das Pluszeichen (+) genau dienen?

Und wie würde der Befehl anders funktionieren, wenn sie vom Befehl ausgeschlossen wären?

find . -type d -exec chmod 775 {} +
Ryan Prentiss
quelle

Antworten:

19

Die geschweiften Klammern werden durch die Ergebnisse des findBefehls ersetzt und chmodauf jedem von ihnen ausgeführt. Die +Marken findversuchen , so wenige Befehle wie möglich (so laufen , chmod 775 file1 file2 file3im Gegensatz zu chmod 755 file1, chmod 755 file2, chmod 755 file3). Ohne sie gibt der Befehl nur einen Fehler aus. Dies wird alles erklärt in man find:

-exec command ;

      Befehl ausführen ; true, wenn der Status 0 zurückgegeben wird. Alle folgenden Argumente findgelten als Argumente für den Befehl, bis ein aus ' ;' bestehendes Argument gefunden wird. Die Zeichenfolge ' {}' wird durch den aktuellen Dateinamen ersetzt, der überall dort verarbeitet wird, wo er in den Argumenten des Befehls vorkommt, nicht nur in Argumenten, in denen er alleine ist, wie in einigen Versionen von find. …

-exec command {} +

      Diese Variante der -execAktion führt den angegebenen Befehl für die ausgewählten Dateien aus, die Befehlszeile wird jedoch erstellt, indem jeder ausgewählte Dateiname am Ende angehängt wird. Die Gesamtzahl der Aufrufe des Befehls ist viel geringer als die Anzahl der übereinstimmenden Dateien. …

terdon
quelle
12

Zusätzlich zu Terdons Antwort

  • "Offensichtlich" -exec …muss entweder mit einem Semikolon ( ;) oder einem Pluszeichen ( +) abgeschlossen werden. Semikolons ist ein Sonderzeichen in der Schale (oder zumindest jede Schale ich je benutzt habe), so, wenn es verwendet werden soll als Teil des findBefehls , muss er entkommen oder zitiert werden ( \;, ";"oder ';').
  • Mit -exec … ;kann die {}Zeichenfolge beliebig oft im Befehl vorkommen, einschließlich null oder zwei oder mehr an einer beliebigen Position.  In diesem Beispiel erfahren Sie, warum Sie möglicherweise auf die -execVerwendung von verzichten möchten {}.   Mit zwei oder mehr Erscheinungen ist nützlich , vor allem , weil in (mindestens) einige Versionen von find, der {}brauchte kein Wort von mir zu sein; es kann andere Zeichen am Anfang oder am Ende haben; z.B,

    find . -type f -exec mv {} {}.bak ";"
    

    Mit -exec … +der {}Zeichenfolge muss erscheinen als letztes Argument vor dem +. Ein Befehl wie

    find . -name "*.bak" -exec mv {} backup_folder +
    

    führt zu einer rätselhaften find: missing argument to ‘-exec’Fehlermeldung.

    • Eine für die Befehle cpund spezifische mvProblemumgehung ist

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      oder

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    Das {}muss ein Wort für sich sein; Es darf am Anfang oder am Ende keine anderen Zeichen enthalten. Und in (zumindest) einigen Versionen von findhaben Sie möglicherweise nicht mehr als eine {}.

  • Ein vernünftiger Hinweis: Sie können sagen

    finden . -name "* .sh" -type f -executable -exec {} optionale Argumente hier ";"

    jedes Ihrer Skripte ausführen. Aber

    finden . -name "* .sh" -Typ f -ausführbar -exec {} +

    Führt eines Ihrer Skripte mit den Namen aller anderen als Parametern aus. Das ist ähnlich zu sagen

    ./*.sh
    

    Als Shell-Befehl findgarantiert except nicht, dass die Ergebnisse sortiert werden. Sie können also nicht sicher sein, dass Sie aaa.sh (Ihre alphabetisch erste *.shDatei) wie gewohnt ausführen ./*.sh.

  • Ein Aspekt, der findAnfängern möglicherweise nicht ganz klar ist, ist, dass die Befehlszeile effektiv eine ausführbare Anweisung in einer arkanen Sprache ist. Beispielsweise,

    find . -name "*.sh" -type f -executable -print
    

    meint

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    oder einfach,

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    Einige der -Schlüsselwörter sind sowohl eine ausführbare Aktion als auch ein Test. Dies gilt insbesondere für -exec … ;; beispielsweise,

    find . -type f -exec grep -q cat {} ";" -print
    

    wird übersetzt in

    für jede Datei
        Wenn es sich um eine einfache Datei handelt (dh nicht um ein Verzeichnis)
        dann
            Führen Sie grep -q cat filename aus
            wenn der Prozess erfolgreich ist (dh mit Status 0 beendet wird)
            dann
                Drucken Sie den Dateinamen
            ende wenn
        ende wenn
    Schleife beenden

    Dadurch werden die Namen aller Dateien gedruckt, die die Zeichenfolge " cat" enthalten. Dies ist grepzwar für sich allein möglich (mit der Option -l(Kleinbuchstaben L)), es kann jedoch nützlich sein, sie findzum Suchen von Dateien zu verwenden, die eine bestimmte Zeichenfolge enthalten UND eine bestimmte Größe aufweisen UND einem bestimmten Eigentümer gehören UND wurden in einem bestimmten Zeitbereich geändert,….

    Dies funktioniert jedoch nicht für -exec … +. Da -exec … +ein Befehl für mehrere Dateien ausgeführt wird, ist es nicht sinnvoll, ihn als logische Bedingung in einer for each file …Schleife zu verwenden.

  • Die Kehrseite des oben findGesagten ist, dass das Programm im Allgemeinen mit dem Beendigungsstatus 0 beendet wird, es sei denn, Sie geben ungültige Argumente an oder es stößt auf ein Verzeichnis, das nicht gelesen werden kann. Selbst wenn ein Programm, das Sie ausführen, fehlschlägt (mit einem Exit-Status ungleich Null beendet), findwird es mit einem Exit-Status von 0 beendet. Es sei  denn,  ein Programm, das Sie ausführen, -exec … +schlägt fehl (mit einem Exit-Status ungleich Null beendet), findwird beendet mit einem Ausgangsstatus ungleich Null.

Zusätzlich zu einer Million Versionen find(1) und Tests der findtatsächlichen Funktionsweise einiger Systeme enthielt The Open Group Base Specifications, Ausgabe 7, Ausgabe 2013 , einige Informationen darüber, was getan werden findmuss, darf und was nicht.

G-Man sagt, "Monica wiedereinsetzen"
quelle
3
... -exec mv {} {}.bak ...Beachten Sie, dass Ihr Beispiel nicht bei allen findImplementierungen erwartungsgemäß funktioniert . Die POSIX-Standardzustände {}müssen einzeln angezeigt werden, um immer erkannt zu werden. Andernfalls kann das Verhalten die Zeichen unverändert lassen oder durch den Pfadnamen ersetzen. Im ersten Fall löscht Ihr gesamter Befehl im Wesentlichen alle Dateien außer den zuletzt gefundenen ...
jlliagre