Wie kann ich Dateien finden und sie dann mit xargs verschieben?

28

Ich möchte einige Dateien finden und sie dann verschieben.

Ich kann die Datei finden mit:

$ find /tmp/ -ctime -1 -name x*

Ich habe versucht, sie in mein ~/playVerzeichnis zu verschieben:

$ find /tmp/ -ctime -1 -name x* | xargs mv ~/play/

aber das hat nicht funktioniert. Offensichtlich braucht mv zwei Argumente.
Sie sind sich nicht sicher, ob (oder wie) Sie auf das 'aktuelle Element' von xargs im Befehl mv verweisen sollen?

Michael Durrant
quelle
3
Warum? Sie können Platzhalter mit -I: verwenden find . | xargs -I'{}' mv '{}' ~/play/, aber wie der Mensch sagt, bedeutet das " -xund -L 1". Also kein Gewinn. Besser einfach halten und verwendenfind . -exec mv '{}' ~/play/ \;
manatwork
Bitte posten Sie als Antwort, um Stimmen zu sehen, wenn es Ihnen nichts ausmacht :)
Michael Durrant
Ich habe nur nach deinem Grund gefragt, da ich das Gefühl hatte, dass ich den Punkt nicht verstanden habe. Wenn Drav Sloan den Vermerk zu den impliziten Optionen hinzufügt, wird seine Antwort so gut wie möglich sein. Also geh besser damit.
Manatwork
mögliches Duplikat von Find pattern and move
slm
@manatwork Ich habe meine Antwort bearbeitet, um diese Punkte zu reflektieren duder :)
Drav Sloan

Antworten:

43

Schauen Sie sich Stephanes Antwort für die beste Methode an und meine Antwort aus Gründen, die naheliegenderen Lösungen nicht zu verwenden (und aus Gründen, warum sie nicht die effizientesten sind).

Sie können folgende -IOptionen verwenden xargs:

find /tmp/ -ctime -1 -name "x*" | xargs -I '{}' mv '{}' ~/play/

Welches funktioniert in einem ähnlichen Mechanismus wie findund {}. Ich würde auch Ihr -nameArgument zitieren (weil eine Datei, die mit xim vorliegenden Verzeichnis beginnt, dateiglobiert und als zu suchendes Argument übergeben würde - was nicht das erwartete Verhalten ergibt!).

Wie jedoch durch manatwork ausgeführt, wie in der xargsManpage beschrieben:

   -I replace-str
          Replace occurrences of replace-str in the initial-arguments with
          names read from standard input.  Also, unquoted  blanks  do  not
          terminate  input  items;  instead  the  separator is the newline
          character.  Implies -x and -L 1.

Die wichtige Sache zu beachten ist , dass -L 1Mittel , die nur eine Zeile der Ausgabe von findzu einem Zeitpunkt bearbeitet werden. Das heißt, das ist syntaktisch dasselbe wie:

find /tmp/ -ctime -1 -name "x*" -exec mv '{}' ~/play/

(der eine einzelne mvOperation für jede Datei ausführt ).

Sogar die Verwendung des GNU- -0Arguments xargs und des find -print0Arguments verursacht genau dasselbe Verhalten von -I- dies ist clone()ein Prozess für jede Datei mv:

find . -name "x*" -print0 | strace xargs -0 -I '{}' mv '{}' /tmp/other

.
.
read(0, "./foobar1/xorgslsala11\0./foobar1"..., 4096) = 870
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =     0x7fbb82fad000
open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=26066, ...}) = 0
mmap(NULL, 26066, PROT_READ, MAP_SHARED, 3, 0) = 0x7fbb82fa6000
close(3)                                = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 661
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 661
--- SIGCHLD (Child exited) @ 0 (0) ---
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 662
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 662
--- SIGCHLD (Child exited) @ 0 (0) ---
.
.
.
Drav Sloan
quelle
Dies setzt voraus, dass Dateinamen keine Zeilenumbrüche, einfachen Anführungszeichen, doppelten Anführungszeichen oder Backslash-Zeichen enthalten.
Stéphane Chazelas
17

Mit GNU-Tools:

find /tmp/ -ctime -1 -name 'x*' -print0 |
  xargs -r0 mv -t ~/play/

Die -t( --target) Option ist GNU-spezifisch. -print0, -r, -0, Während Nicht-Standard , mit Ursprung in GNU ist auch in einigen anderen Implementierungen wie auf einigem BSDs gefunden.

POSIXly:

find /tmp/ -ctime -1 -name 'x*' -exec sh -c '
  exec mv "$@" ~/play/' sh {} +

Beide führen so wenige mvBefehle wie nötig aus und funktionieren mit allen Zeichen, die der Dateiname enthalten kann. Die GNU one hat möglicherweise den Vorteil, dass sie findständig nach Dateien sucht, während mvsie den ersten Stapel verschiebt.

Beachten Sie, dass alle Dateien und Verzeichnisse in einem Verzeichnis landen. Achten Sie auf Konflikte, wenn mehrere Dateien in verschiedenen Verzeichnissen denselben Namen haben.

Stéphane Chazelas
quelle
Diese Lösung ist viel leistungsfähiger, da mvalle Argumente (oder alle -Loder -n, falls angegeben) einmal abgefragt werden. Andernfalls wird das Aufrufen mvjeder Datei schnell alt (und langsam).
r2evans
1

Vielleicht ist dieser Befehl jetzt möglich und war 2013 noch nicht verfügbar, aber das funktioniert perfekt für mich:

ls pattern* | xargs mv -t DESTINATION/

Die -tTaste setzt den Zielordner an die erste Stelle und gibt den mvBefehl frei, um alle letzten Argumente als nur die zu verschiebenden Dateien zu haben.

Nikhil VJ
quelle
1
Dies war die einfachste Lösung, die für mich funktioniert hat
ptetteh227
0

Sie können mit dem folgenden Befehl versuchen und getestet und es hat gut funktioniert

find /tmp/ -ctime -1 -type f -name "x*" -exec mv -t ~/play/ {} \;
Praveen Kumar BS
quelle