Como integrar o comando mv após o comando find?

44

Estou pesquisando arquivos cujo nome contenha AAA em seu caminho usando o seguinte comando:

find path_A -name "*AAA*"

Dada a saída mostrada pelo comando acima, quero mover esses arquivos para outro caminho, digamos path_B . Em vez de mover esses arquivos um por um, posso otimizar o comando movendo esses arquivos logo após o comando find?

    
por huahsin68 10.09.2014 / 15:55

6 respostas

62

Com o GNU mv :

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

Isso usará a opção -exec do find, que substituirá o {} por cada resultado de busca e executará o comando fornecido. Conforme explicado em 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.  

Nesse caso, estamos usando a versão + de -exec para que possamos executar o mínimo de mv operações:

   -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.
    
por 10.09.2014 / 15:58
16

Você também pode fazer algo como abaixo.

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

Onde,

  1. -0 Se houver espaços em branco ou caracteres (incluindo novas linhas), muitos comandos não funcionarão. Esta opção toma cuidado com nomes de arquivos espaço em branco.
  2. -I Substitui ocorrências de replace-str nos argumentos iniciais com nomes lidos da entrada padrão. Além disso, os espaços em branco não citados não terminar itens de entrada; em vez disso, o separador é a nova linha personagem.

Teste

Eu criei dois diretórios como sourcedir e destdir . Agora, criei vários arquivos dentro de sourcedir as file1.bak , file2.bak e file3 with spaces.bak

Agora, eu executei o comando como

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

Agora, dentro do destdir , quando eu faço ls , pude ver que os arquivos foram movidos de sourcedir para destdir .

Referências

link

    
por 10.09.2014 / 16:28
13

Para o benefício dos usuários do OS X que se deparam com essa questão, a sintaxe no OS X é um pouco diferente. Supondo que você não queira pesquisar recursivamente em subdiretórios de path_A :

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

Se você quiser pesquisar todos os arquivos recursivamente em path_A :

find path_A -name "*AAA*" -exec mv {} path_B \;
    
por 26.08.2016 / 05:26
6

O -exec é a melhor maneira de fazer isso. Se, por qualquer motivo, isso não for uma opção, você também poderá ler os resultados em um loop:

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

Esse é o modo seguro, ele pode lidar com nomes de arquivos que contenham espaços, novas linhas ou outros caracteres estranhos. Uma maneira mais simples, mas que falha, a menos que seus nomes de arquivo consistam apenas em caracteres alfanuméricos simples , é

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

Mas use o loop while.

    
por 10.09.2014 / 16:13
4

Usando apenas os recursos POSIX de find (e also de mv ):

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

Leitura adicional:

por 09.11.2016 / 09:46
2

Outra maneira

for f in 'find path_A -name "*AAA*"'; do mv $f /destination/dir/; done
    
por 26.08.2016 / 05:28

Tags