web-dev-qa-db-fra.com

Comment intégrer la commande mv après la commande find?

Je recherche des fichiers dont le nom contient AAA dans leur chemin en utilisant la commande suivante:

find path_A -name "*AAA*"

Étant donné la sortie affichée par la commande ci-dessus, je souhaite déplacer ces fichiers vers un autre chemin, par exemple path_B. Au lieu de déplacer ces fichiers un par un, puis-je optimiser la commande en déplaçant ces fichiers juste après la commande find?

67
huahsin68

Avec GNU mv :

find path_A -name '*AAA*' -exec mv -t path_B {} +

Cela utilisera l'option -exec De find qui remplace le {} Avec chaque résultat de recherche à son tour et exécute la commande que vous lui donnez. Comme expliqué dans man find:

   -exec command ;
          Execute  command;  true  if 0 status is returned.  All following
          arguments to find are taken to be arguments to the command until
          an  argument  consisting of `;' is encountered.  

Dans ce cas, nous utilisons la version + De -exec Afin d'exécuter le moins d'opérations mv possible:

   -exec command {} +
          This  variant  of the -exec action runs the specified command on
          the selected files, but the command line is built  by  appending
          each  selected file name at the end; the total number of invoca‐
          tions of the command will  be  much  less  than  the  number  of
          matched  files.   The command line is built in much the same way
          that xargs builds its command lines.  Only one instance of  `{}'
          is  allowed  within the command.  The command is executed in the
          starting directory.
96
cuonglm

Vous pouvez également faire quelque chose comme ci-dessous.

find path_A -name "*AAA*" -print0 | xargs -0 -I {} mv {} path_B

Où,

  1. -0 S'il y a des espaces ou des caractères vides (y compris les retours à la ligne), de nombreuses commandes ne fonctionneront pas. Cette option prend soin des noms de fichiers avec un espace vide.
  2. -I Remplacez les occurrences de replace-str dans les arguments initiaux par des noms lus à partir de l'entrée standard. De plus, les espaces non entre guillemets ne terminent pas les éléments d'entrée; à la place, le séparateur est le caractère de nouvelle ligne.

Test

J'ai créé deux répertoires comme sourcedir et destdir. Maintenant, j'ai créé un tas de fichiers dans sourcedir en tant que file1.bak, file2.bak et file3 with spaces.bak

Maintenant, j'ai exécuté la commande comme,

find . -name "*.bak" -print0 | xargs -0 -I {} mv {} /destdir/

Maintenant, à l'intérieur de destdir, quand je fais ls, je pouvais voir que les fichiers étaient passés de sourcedir à destdir.

Références

http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/

25
Ramesh

Pour le bénéfice des utilisateurs d'OS X rencontrant cette question, la syntaxe dans OS X est légèrement différente. En supposant que vous ne vouliez pas effectuer de recherche récursive dans les sous-répertoires de path_A:

find path_A -maxdepth 1 -name "*AAA*" -exec mv {} path_B \;

Si vous souhaitez rechercher récursivement tous les fichiers dans path_A:

find path_A -name "*AAA*" -exec mv {} path_B \;
23
mannykary

Le -exec est la meilleure façon de procéder. Si, pour une raison quelconque, ce n'est pas une option, vous pouvez également lire les résultats dans une boucle:

find path_A -name "*AAA*" -print0 | 
    while IFS= read -r -d $'\0' file; do mv "$file" path_B; done

C'est le moyen sûr, il peut traiter les noms de fichiers qui contiennent des espaces, des nouvelles lignes ou d'autres caractères étranges. Une manière plus simple, mais qui échoue à moins que vos noms de fichiers ne soient composés que de caractères alphanumériques simples, est

mv $(find path_A -name "*AAA*") path_B

Mais utilisez la boucle while.

6
terdon

Utiliser uniquement fonctionnalités POSIX de find (et également de mv ):

find path_A -name '*AAA*' -exec sh -c 'mv "$@" path_B' find-sh {} +

Lectures complémentaires:

5
Wildcard

Autrement

for f in `find path_A -name "*AAA*"`; do mv $f /destination/dir/; done
2
user13107