Mit Exec können wir entweder alle Argumente gleichzeitig mit {} +
oder einzeln übergeben{} \;
Nehmen wir jetzt an, ich möchte alle JPEGs umbenennen , kein Problem dabei:
find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec mv '{}' '{}'.new \;
Wenn ich jedoch eine Ausgabe umleiten muss, kann ich nach der Umleitung '{}'
nicht darauf zugreifen.
find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec cjpeg -quality 80 '{}' > optimized_'{}' \;
Das würde nicht funktionieren. Ich müsste eine for-Schleife verwenden und die Ausgabe von find in einer Variablen speichern, bevor ich sie verwenden kann. Lassen Sie es uns zugeben, es ist umständlich.
for f in `find . \( -name '*.jpg' -o -name '*.jpeg' \)`; do cjpeg -quality 80 $f > optimized_$f; done;
Gibt es einen besseren Weg?
>
in der dritten Codebeispiel fehlt?{}
die in längeren Zeichenfolgen angezeigt werden, da solche Zeichenfolgen normalerweise nicht erweitert werden.find
einmal starten und auf denfind
Befehl selbst anwenden . Das{}
hat in diesem Zusammenhang keine besondere Bedeutung. Die Umleitung ist kein Argument dafürfind
und sicherlich nicht Teil der-exec
Klausel.Antworten:
Sie können
bash -c
innerhalb desfind -exec
Befehls den Positionsparameter mit dem Befehl bash verwenden:Auf diese Weise
{}
ist mit versehen$1
.Die
sh
vor dem{}
erzählt die innere Schale seinen „Namen“, verwendete die Zeichenfolge hier in zB Fehlermeldungen verwendet. Dies wird in dieser Antwort zum Stapelüberlauf näher erläutert .quelle
Sie haben eine Antwort ( https://unix.stackexchange.com/a/481687/4778 ), aber hier ist der Grund.
Die Umleitung
>
sowie Pipes|
und$
Erweiterungen werden alle von der Shell ausgeführt, bevor der Befehl ausgeführt wird. Daher wird stdout umgeleitetoptimized_{}
, bevorfind
es gestartet wird.quelle
Die Umleitung muss in Anführungszeichen gesetzt werden, um zu vermeiden, dass die vorliegende Shell sie interpretiert.
Durch das Zitieren wird jedoch auch vermieden, dass die Ausgabe des Befehls umgeleitet wird.
Die bekannte Lösung hierfür besteht darin, eine Shell aufzurufen:
In diesem Fall wird die Umleitung (
>
) in der aktuellen Shell in Anführungszeichen gesetzt und funktioniert in der aufgerufenen Shell ordnungsgemäß. Dascalled_shell
wird als$0
Parameter (der Name) der untergeordneten Shell (sh
) verwendet.Das funktioniert gut, wenn ein Suffix mit dem Namen der Datei hinzugefügt wird, aber nicht, wenn Sie ein Präfix verwenden. Damit ein Präfix funktioniert, müssen Sie sowohl das Präfix für
./
Dateinamen entfernen als auch${1#./}
die-execdir
Option verwenden.Sie kann (oder auch nicht) will die verwenden
-iname
Option , so dass Dateien mit dem Namen*.JPG
oder*.JpG
oder andere Variationen sind ebenfalls enthalten.Möglicherweise möchten Sie die Shell auch einmal pro Verzeichnis anstatt einmal pro Datei aufrufen (oder auch nicht), indem Sie am Ende eine Schleife (
for f do … ; done
) und eine hinzufügen+
:Und schließlich, da
cjpeg
direkt in eine Datei geschrieben werden kann, könnte die Umleitung wie folgt vermieden werden:quelle
cjpeg
hat eine Option, mit der Sie in eine benannte Datei anstatt in eine Standardausgabe schreiben können. Wenn Ihre Version von diese Optionfind
unterstützt-execdir
, können Sie dies nutzen, um die Umleitung unnötig zu machen.Hinweis: Dies setzt tatsächlich die BSD-Version von voraus
find
, die./
beim Erweitern auf den führenden Namen vom Dateinamen zu entfernen scheint{}
. (Oder umgekehrtfind
fügt GNU./
dem Namen hinzu. Es gibt keinen Standard, um zu sagen, welches Verhalten "richtig" ist.)quelle
find
Unterstützung-execdir
, können Sie das anstelle von verwenden-exec
. Der Befehl wird in dem Verzeichnis ausgeführt, in dem die Datei gefunden wurde, und{}
wirdaa.jpg
stattdessen anstelle von./t2/aa.jpg
.cjpeg: can't open optimized_./aa.jpg
.find
und BSD zu seinfind
. (Die Gefahren der Verwendung von nicht standardmäßigen Erweiterungen.)./
scheint fehleranfälliger zu sein. In dieser Antwort wird eine vernünftige Lösung vorgeschlagen .Erstellen Sie ein Skript cjq80:
Mach es ausführbar
Und benutze es in -exec:
quelle