GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum funktioniert find -exec mv {} ./target/ + nicht?

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).


Linux
  1. Wie behandelt Linux mehrere aufeinanderfolgende Pfadtrennzeichen (/home////username///file)?

  2. Warum funktioniert `exit &` nicht?

  3. 12.04 Fehler beim Installieren von Grub-efi nach /target/?

  4. Installieren Sie Binärdateien in /bin, /sbin, /usr/bin und /usr/sbin, Interaktionen mit --prefix und DESTDIR

  5. Wie finde ich heraus, aus welchem ​​Ordner ein Prozess läuft?

Linux – /sbin/init existiert nicht?

Warum funktioniert diese Regex nicht unter Linux?

Warum andere Dinge als /home auf eine separate Partition legen?

/sys/ Dokumentation?

echo oder print /dev/stdin /dev/stdout /dev/stderr

Warum haben die Verzeichnisse /home, /usr, /var usw. alle dieselbe Inode-Nummer (2)?