Ich versuche, den folgenden Befehl auszuführen:
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +
Dies gibt einen Fehler zurück:
find: missing argument to -exec
Ich kann nicht erkennen, was an diesem Befehl falsch ist, da er mit der Manpage übereinzustimmen scheint:
-exec Befehl {} +
Diese Variante der Option -exec 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. Die Befehlszeile wird auf die gleiche Weise erstellt wie xargs seine Befehlszeilen erstellt. Innerhalb des Befehls ist nur eine Instanz von „{}“ zulässig. Der Befehl wird im Startverzeichnis ausgeführt.
Ich habe auch versucht:
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
Antwort1
Bei Ihren Versuchen traten mehrere Probleme auf, darunter die Verwendung von Backticks anstelle von Anführungszeichen (in späteren Änderungen der Frage entfernt), fehlende Anführungszeichen an erforderlichen Stellen, zusätzliche Anführungszeichen an nutzlosen Stellen, fehlende Klammern zum Gruppieren von -o
Klauseln und unterschiedliche verwendete Implementierungen find
(weitere Einzelheiten finden Sie in den Kommentaren und im Chat).
Der Befehl kann jedoch folgendermaßen vereinfacht werden:
find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +
oder, falls Sie eine veraltete GNU-Find-Version verwenden, sollte dies immer funktionieren:
find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;
Antwort2
„fehlendes Argument für -exec
“ bedeutet normalerweise, dass dem Argument für - exec
sein Abschlusszeichen fehlt. Das Abschlusszeichen muss entweder ein Argument sein, das nur das Zeichen enthält ;
(das in einem Shell-Befehl in Anführungszeichen gesetzt werden muss, also normalerweise \;
oder geschrieben wird ';'
), oder zwei aufeinanderfolgende Argumente, die {}
und enthalten +
.
Stephane Chazelas hat festgestelltdass Sie eine ältere Version von GNU find verwenden, die nicht unterstützt -exec … {} +
, sondern nur -exec {} \;
. Obwohl GNU ein später Anwender von war -exec … {} +
, empfehle ich Ihnen, eine weniger veraltete Tool-Suite zu verwenden (wie etwaCygwin, das git und vieles mehr beinhaltet, oderGNUwin32, dem Git fehlt, das aber nicht den Eindruck vermittelt, dass ein schlechter Mitarbeiter versucht, Linux zu verwenden, aber wir zwingen ihm Windows auf, wie es Cygwin vermittelt. Diese Funktion wurde vor über 9 Jahren in Version 4.2.12 hinzugefügt (es war die letzte bekannte Funktion, die GNU find
POSIX-kompatibel machte).
Wenn Sie bei einem älteren GNU-Find bleiben möchten, können Sie -print0
with verwenden xargs -0
, um eine ähnliche Funktionalität zu erhalten: gruppierte Befehlsausführung, Unterstützung beliebiger Dateinamen.
find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null
Setzen Sie die Platzhalter in der Befehlszeile immer in Anführungszeichen. Andernfalls wird, wenn Sie diesen Befehl aus einem Verzeichnis mit Dateien find
ausführen , die nicht in Anführungszeichen gesetzten Zeichen in die Liste der Dateien im aktuellen Verzeichnis erweitert ..c
*.c
.c
Das Hinzufügen /dev/null
zur grep
Befehlszeile ist ein Trick, um sicherzustellen, dass grep immer den Dateinamen ausgibt, selbst wenn find
nur eine einzige Übereinstimmung gefunden wird. Bei GNU find besteht eine andere Methode darin, die Option zu übergeben -H
.
Antwort3
Wenn ein Befehl wie
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +
gibt Fehler zurück
find: missing argument to -exec
Die wahrscheinliche Ursache ist ein zu altes GNU find
, das die Syntax nicht unterstützt -exec mycommand {} +
. In diesem Fall muss ein Ersatz mit geringer Leistung ausgeführt werden -exec mycommand {} \;
, der für jedes gefundene Ziel einmal ausgeführt wird mycommand
, anstatt mehrere Ziele zu sammeln und mycommand
nur einmal auszuführen.
Allerdings find
unterstützt GNU nicht zB
find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +
weil GNU find
nur wörtliche Kombinationen unterstützt {} +
und keine allgemeineren {} additional parameters +
. Beachten Sie, dass zwischen den Klammern und dem Zeichen nichts stehen darf +
. Wenn Sie dies versuchen, erhalten Sie denselben Fehler:
find: missing argument to -exec
Der Workaround besteht darin, eine Syntax zu verwenden {} additional parameters \;
, die zwar funktioniert, den Befehl aber einmal für jedes gefundene Ziel ausführt. Wenn Sie mit GNU mehr Leistung benötigen, find
müssen Sie ein Wrapper-Skript schreiben, das zusätzliche Parameter an die angegebenen Argumente anhängen kann. So etwas wie
#!/bin/bash
exec mycommand "$@" additional parameters
sollte gut genug sein. Oder, wenn Sie keine temporäre Datei erstellen möchten, können Sie die Reihenfolge der Parameter mit einem Einzeiler wie folgt ändern:
find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +
wodurch ausgeführt wird mycommand {list of ttf files} extra arguments
. Beachten Sie, dass Sie Sonderzeichen für die Bash nach dem -c
Flag möglicherweise doppelt escapen müssen.
Antwort4
Ich hatte in der Vergangenheit jede Menge Kopfschmerzen mit der Exec-Syntax. Heutzutage bevorzuge ich an den meisten Tagen die schönere Bash-Syntax:
for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done
Es gibt einige Einschränkungen, wenn Sie die Dateien als Gruppe behandeln möchten, da jede seriell ausgewertet wird, aber Sie können die Ausgabe problemlos an eine andere Stelle weiterleiten