Comment puis-je trouver des fichiers et ensuite utiliser xargs pour les déplacer?

28

Je veux trouver des fichiers et les déplacer.

Je peux trouver le fichier avec:

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

J'ai essayé de les déplacer dans mon ~/playrépertoire avec:

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

mais cela n'a pas fonctionné. Evidemment mv a besoin de deux arguments.
Vous ne savez pas si (ou comment) référencer l'élément actuel de xargs dans la commande mv?

Michael Durrant
la source
3
Pourquoi? Vous pouvez utiliser l' espace réservé avec -I: find . | xargs -I'{}' mv '{}' ~/play/, mais comme homme dit que « Implique -xet -L 1. » Donc , pas de gain. Mieux vaut rester simple et utiliserfind . -exec mv '{}' ~/play/ \;
manatwork
Veuillez poster comme réponse pour voir les votes si cela ne vous dérange pas :)
Michael Durrant
Je vous ai juste demandé votre raison, car j'avais l'impression que je n'avais pas compris. Si Drav Sloan ajoute la note sur les options implicites, sa réponse sera aussi bonne que la meilleure que j'ai pu écrire. Donc, mieux vaut aller avec ça.
manatwork
doublon possible du motif
slm
@manatwork J'ai édité ma réponse pour refléter ces points duder :)
Drav Sloan

Réponses:

43

Regardez la réponse de Stéphane pour la meilleure méthode, regardez ma réponse pour des raisons de ne pas utiliser les solutions les plus évidentes (et les raisons pour lesquelles elles ne sont pas les plus efficaces).

Vous pouvez utiliser l' -Ioption de xargs:

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

Qui fonctionne dans un mécanisme similaire à findet {}. Je citerais également votre -nameargument (car un fichier commençant par xdans le répertoire actuel serait globalisé et passé en argument à rechercher - ce qui ne donnera pas le comportement attendu!).

Cependant, comme l'a souligné Manatwork, comme détaillé dans la xargspage de manuel:

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

La chose importante à noter est que cela -L 1signifie qu'une seule ligne de sortie findsera traitée à la fois. Cela signifie que c'est syntaxiquement le même que:

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

(qui exécute une seule mvopération pour chaque fichier).

Même en utilisant l' -0argument GNU xargs et l' find -print0argument provoque exactement le même comportement de -I- il s'agit d' clone()un processus pour chaque fichier 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
la source
Cela suppose que les noms de fichiers ne contiennent pas de caractères de nouvelle ligne, de guillemet simple, de guillemet double ou de barre oblique inverse.
Stéphane Chazelas
17

Avec les outils GNU:

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

L' option -t( --target) est spécifique à GNU. -print0, -r, -0, Tandis que les non-standard et originaires de GNU se trouvent également dans d'autres implémentations comme sur certains BSDs.

POSIX:

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

Les deux exécutent aussi peu de mvcommandes que nécessaire et fonctionnent quels que soient les caractères que les noms de fichiers peuvent contenir. Le GNU peut avoir l'avantage de findcontinuer à chercher des fichiers tout en mvcommençant à déplacer le premier lot.

Attention, tous les fichiers et répertoires se retrouveront dans un seul répertoire, attention aux conflits si plusieurs fichiers dans des répertoires différents portent le même nom.

Stéphane Chazelas
la source
Cette solution est beaucoup plus performante, car elle appelle mvune fois pour tous les arguments (ou pour tout -Lou -n, si fourni). Sinon, appeler mvpour chaque fichier vieillira (et ralentira) rapidement.
r2evans
1

Peut-être que cette commande est possible maintenant et n'était pas de retour en 2013, mais cela fonctionne parfaitement pour moi:

ls pattern* | xargs mv -t DESTINATION/

La -tclé place le dossier de destination en premier, libérant la mvcommande pour avoir tous les derniers arguments comme juste les fichiers à déplacer.

Nikhil VJ
la source
1
ce fut la solution la plus simple qui a fonctionné pour moi
ptetteh227
0

Vous pouvez essayer avec la commande ci-dessous et testé et cela a bien fonctionné

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