`find` with multiple` -name` und `-exec` führen nur die letzten Übereinstimmungen von` -name` aus

74

Wenn ich benutze

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt"

Es findet alle Dateitypen. Aber wenn ich -execam Ende hinzufüge :

find . -type f -name "*.htm*" -o -name "*.js*" -o -name "*.txt" -exec sh -c 'echo "$0"' {} \;

es scheint, dass es nur .txtDateien druckt . Was mache ich falsch?

Hinweis: Verwenden von MINGW (Git Bash)

jakub.g
quelle
Hinweis: Der erste Befehl gibt auch Verzeichnisse aus, deren Namen mit *.js*oder übereinstimmen *.txt.
Wildcard

Antworten:

99
finden . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt"

ist kurz für:

finden . \ (\ ( -Typ f -a -name "* .htm *" \) -o \
          \ ( -name "* .js *" \) -o \
          \ ( -name "* .txt" \) \
       \) -Ein Druck

Das heißt, da kein Aktionsprädikat angegeben ist (nur Bedingungen ), -printwird implizit eine Aktion für die Dateien hinzugefügt, die den Bedingungen entsprechen.

(und das würde übrigens nicht reguläre .jsDateien drucken (das -type fgilt nur für .htmDateien)).

Während:

finden . -type f -name "* .htm *" -o -name "* .js *" -o -name "* .txt" \
  -exec sh -c 'echo "$ 0"' {} \;

ist kurz für:

finden . \ ( -type f -a -name "* .htm *" \) -o \
       \ ( -name "* .js *" \) -o \
       \ ( -name "* .txt" -a -exec sh -c 'echo "$ 0"' {} \; \)

Für find(wie in vielen Sprachen) hat AND ( -aimplizit, wenn weggelassen) Vorrang vor OR ( -o), und das Hinzufügen eines expliziten Aktionsprädikats (hier -exec) bricht die -printoben gezeigte implizite Aktion ab. Hier möchten Sie:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) \
  -exec sh -c 'echo "$0"' {} \;

Oder:

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c '
   for i do
     echo "$i"
   done' sh {} +

Um zu vermeiden, dass eine shDatei pro Datei ausgeführt wird.

Stéphane Chazelas
quelle
In einigen dieser sh -c-Verwendungen müssen Sie das nullte Argument für sh hinzufügen (in anderen haben Sie es bereits eingeschlossen).
James Youngman
1
Das ist eine großartige Antwort!
Marinos An
30

Es sind die implizierten Klammern. Fügen Sie explizite Klammern hinzu.\( \)

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -exec sh -c 'echo "$0"' {} \;

oder mit xargs (ich mag xargs ich finde es einfacher, aber anscheinend nicht so portabel).

find . -type f \( -name "*.htm*" -o -name "*.js*" -o -name "*.txt" \) -print0 | xargs -0 -n1 echo
Strg-Alt-Delor
quelle