Ich habe das gleiche Problem auf Mac OSX festgestellt , mit einem ZSH Shell:In diesem Fall gibt es kein -t
Option für mv
, also musste ich eine andere Lösung finden. Der folgende Befehl war jedoch erfolgreich:
find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \;
Das Geheimnis war, die geschweiften Klammern zu zitieren . Die geschweiften Klammern müssen nicht am Ende von exec
stehen Befehl.
Getestet habe ich unter Ubuntu 14.04 (mit BASH und ZSH Muscheln), funktioniert es genauso.
Bei Verwendung der +
Zeichen, es scheint tatsächlich, dass es am Ende von exec
stehen muss Befehl.
Die Handbuchseite (oder das Online-GNU-Handbuch) erklärt so ziemlich alles.
find -exec command {} \;
Für jedes Ergebnis command {}
wird ausgeführt. Alle Vorkommen von {}
werden durch den Dateinamen ersetzt. ;
wird ein Schrägstrich vorangestellt, um zu verhindern, dass die Shell ihn interpretiert.
find -exec command {} +
Jedes Ergebnis wird an command
angehängt und danach hingerichtet. Unter Berücksichtigung der Beschränkungen der Befehlslänge denke ich, dass dieser Befehl öfter ausgeführt werden kann, wobei die Handbuchseite mich unterstützt:
Die Gesamtzahl der Aufrufe des Befehls ist viel geringer als die Anzahl der übereinstimmenden Dateien.
Beachten Sie dieses Zitat aus der Handbuchseite:
Die Befehlszeile ist ähnlich aufgebaut wie xargs seine Befehlszeilen
Deshalb sind zwischen {}
keine Zeichen erlaubt und +
außer Leerzeichen. +
lässt find erkennen, dass die Argumente genau wie xargs
an den Befehl angehängt werden sollten .
Die Lösung
Glücklicherweise ist die GNU-Implementierung von mv
kann das Zielverzeichnis als Argument akzeptieren, entweder mit -t
oder der längere Parameter --target
. Seine Verwendung wird sein:
mv -t target file1 file2 ...
Ihr find
Befehl wird zu:
find . -type f -iname '*.cpp' -exec mv -t ./test/ {} \+
Von der Handbuchseite:
-exec-Befehl;
Befehl ausführen; wahr, wenn der Status 0 zurückgegeben wird. Alle folgenden zu findenden Argumente werden als Argumente für den Befehl angesehen, bis ein Argument, das aus `;' angetroffen wird. Die Zeichenkette »{}« wird überall dort, wo sie in den Argumenten des Befehls vorkommt, durch den aktuellen Dateinamen ersetzt, nicht nur in Argumenten, wo sie allein steht, wie in einigen Versionen von find. Diese beiden Konstruktionen müssen möglicherweise maskiert (mit einem »\«) oder in Anführungszeichen gesetzt werden, um sie vor einer Erweiterung durch die Shell zu schützen. Im Abschnitt BEISPIELE finden Sie Beispiele für die Verwendung der Option -exec. Der angegebene Befehl wird einmal für jede übereinstimmende Datei ausgeführt. Der Befehl wird im Startverzeichnis ausgeführt. Es gibt unvermeidliche Sicherheitsprobleme im Zusammenhang mit der Verwendung der Aktion -exec; Sie sollten stattdessen die Option -execdir verwenden.
-exec-Befehl {} +
Diese Variante der Aktion -exec führt den angegebenen Befehl für die ausgewählten Dateien aus, aber die Befehlszeile wird 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 ist ähnlich wie xargs seine Befehlszeilen aufgebaut. Innerhalb des Befehls ist nur eine Instanz von `{}' erlaubt. Der Befehl wird im Startverzeichnis ausgeführt.
Das Standardäquivalent von find -iname ... -exec mv -t dest {} +
für find
Implementierungen, die -iname
nicht unterstützen oder mv
Implementierungen, die -t
nicht unterstützen ist, eine Shell zu verwenden, um die Argumente neu zu ordnen:
find . -name '*.[cC][pP][pP]' -type f -exec sh -c '
exec mv "[email protected]" /dest/dir/' sh {} +
Durch Verwendung von -name '*.[cC][pP][pP]'
vermeiden wir auch die Abhängigkeit vom aktuellen Gebietsschema, um zu entscheiden, was die Großbuchstabenversion von c
ist oder p
.
Beachten Sie, dass +
, im Gegensatz zu ;
ist in keiner Shell etwas Besonderes, muss also nicht in Anführungszeichen gesetzt werden (obwohl Anführungszeichen nicht schaden, außer natürlich bei Shells wie rc
). die \
nicht unterstützen als Zitieroperator).
Das abschließende /
in /dest/dir/
ist also mv
schlägt mit einem Fehler fehl, anstatt foo.cpp
umzubenennen bis /dest/dir
falls nur ein cpp
Datei wurde gefunden und /dest/dir
existierte nicht oder war kein Verzeichnis (oder symbolischer Link zum Verzeichnis).