
Quero usar find para encontrar determinados arquivos e, em seguida, usar xargs com cp e sed para mover esses arquivos para outra pasta e renomeá-los. Eu sei como fazer isso em loop, mas não é isso que estou procurando.
Tentei:
find ${FOLDER} -iname "*${SOME_STRING}*" | xargs -I {} cp {} $(echo {} | sed 's/ABC/XYZ/g')
Por que isso não está funcionando e qual seria a solução?
Responder1
Experimente isso. Não precisa de xargs
, apenas find
, sed
e copy
. Isso não mudará nenhum arquivo, masvaiimprima uma lista de comandos shell para copiar os arquivos. Então, se você gostar dos comandos que ele imprime, execute-o novamente e remova o #
antes sh -x
da última linha e deixe o shell executar os comandos.
find "${FOLDER:-.}" -iname "*${SOME_STRING:-ABC}*" |
sed "
s/^/'/ # surround filename with single quotes
s/$/'/
h # save filename in the sed hold space
s/ABC/XYZ/g # change filename
H # append to hold space (separates with newline)
g # get original and modified from hold
s/\n/ /g # replace the newline with a space
s/^/cp -i/ # make it into a copy command
" #| sh -x # optionally pipe to shell
Por que essa abordagem é melhor do que xargs
neste caso? Porque este método inicia apenas 3 processos no total ( find
,, sed
e sh
) além do cp
comando necessário para cada arquivo.
Para usar xargs
, o processamento de cada nome de arquivo exigiria mais processos do que o único cp
comando necessário.
É muito mais eficiente deixar a única invocação do sed gerartodosdos cp
comandos, do que invocar um novo sed
processo para cada nome de arquivo.
Responder2
Usando GNU Parallel fica assim:
find ${FOLDER} -iname "*${SOME_STRING}*" |
parallel cp {} '{= s/ABC/XYZ/g =}'
A construção {= =} contém uma expressão Perl que altera $_.
Uma das vantagens é que o GNU Parallel faz a coisa certa mesmo se você tiver arquivos chamados:
My brother's 12" records worth >100$.txt
ou horrores como:
touch Y-"$(perl -e 'print pack("c*",1..9,11..46,48..255)')"