Eu quero saber exatamente o que {} \;
e {} \+
e | xargs ...
fazer. Por favor, esclareça isso com explicações.
Abaixo de 3 comandos são executados e geram o mesmo resultado, mas o primeiro comando leva um pouco de tempo e o formato também é um pouco diferente.
find . -type f -exec file {} \;
find . -type f -exec file {} \+
find . -type f | xargs file
É porque o primeiro executa o file
comando para cada arquivo proveniente do find
comando. Então, basicamente funciona como:
file file1.txt
file file2.txt
Mas os 2 últimos achados com -exec
comandos, execute o comando de arquivo uma vez para todos os arquivos como abaixo:
file file1.txt file2.txt
Então eu executo os seguintes comandos em que o primeiro é executado sem problemas, mas o segundo fornece uma mensagem de erro.
find . -type f -iname '*.cpp' -exec mv {} ./test/ \;
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec'
Para o comando com {} \+
, aparece a mensagem de erro
find: missing argument to `-exec'
por que é que? alguém pode explicar o que estou fazendo de errado?
Respostas:
A página de manual (ou o manual GNU online ) explica praticamente tudo.
comando find -exec {} \;
Para cada resultado,
command {}
é executado. Todas as ocorrências de{}
são substituídas pelo nome do arquivo.;
é prefixado com uma barra para evitar que o shell o interprete.comando find -exec {} +
Cada resultado é anexado
command
e executado posteriormente. Levando em conta as limitações de comprimento do comando, acho que este comando pode ser executado mais vezes, com a página do manual me apoiando:Observe esta citação da página do manual:
É por isso que nenhum caractere é permitido entre
{}
e+
exceto para espaços em branco.+
faz o find detectar que os argumentos devem ser acrescentados ao comando da mesma forma quexargs
.A solução
Felizmente, a implementação GNU de
mv
pode aceitar o diretório de destino como um argumento, com um-t
ou o parâmetro mais longo--target
. Seu uso será:Seu
find
comando se torna:Na página do manual:
fonte
./test/
entre{}
e+
, mas nenhum caractere diferente de espaço em branco é permitido entre eles.+
comando é um pouco estranho AFAIU, uma vez que cola os arquivos "no final" (e não no lugar de{}
), então por que usar{}
- isso é confuso. Obrigado pela-t
opção que eu não conhecia, parece que essa opção foi criada como uma solução alternativa para esse-exec +
problema!Encontrei o mesmo problema no Mac OSX , usando um shell ZSH : neste caso não há
-t
opção paramv
, então tive que encontrar outra solução. No entanto, o seguinte comando foi bem-sucedido:O segredo era citar o aparelho . Não há necessidade de as chaves estarem no final do
exec
comando.Eu testei no Ubuntu 14.04 (com shell BASH e ZSH ), funciona da mesma forma.
No entanto, ao usar o
+
sinal, parece de fato que tem que estar no final doexec
comando.fonte
{}
precisa ser citado nos shellsfish
erc
, mas não emzsh
,bash
nem em quaisquer outros shells das famílias Bourne ou csh.bash
, de fato as aspas não são necessárias. Curiosamente, tive um problema ao não citá-los no MacOS (usandozsh
). Mas não tenho um Mac disponível para tentar de novo ...O equivalente padrão de
find -iname ... -exec mv -t dest {} +
parafind
implementações que não oferecem suporte-iname
oumv
implementações que não oferecem suporte-t
é usar um shell para reordenar os argumentos:Ao usar
-name '*.[cC][pP][pP]'
, também evitamos depender da localidade atual para decidir qual é a versão em maiúsculas dec
oup
.Observe que
+
, ao contrário de;
não é especial em nenhum shell, portanto, não precisa ser citado (embora citar não prejudique, exceto, é claro, que shells comorc
esse não suportam\
como um operador de citação).A fuga
/
em/dest/dir/
é para quemv
falha com um erro em vez de renomearfoo.cpp
para/dest/dir
no caso em que apenas umcpp
arquivo foi encontrado e/dest/dir
não existia ou não era um diretório (ou link simbólico para o diretório).fonte
fonte
não, a diferença entre
+
e\;
deve ser revertida.+
anexa os arquivos ao final do comando exec, em seguida, executa o comando exec e\;
executa o comando para cada arquivo.O problema é
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+
quefind . -type f -iname '*.cpp' -exec mv {} ./test/ +
não há necessidade de escapar ou encerrar o+
xargs que não uso há muito tempo, mas acho que funciona como +.
fonte
-name "*.cpp"
Eu dificilmente uso -iname a menos que eu queira fazer alguma pesquisa regex difícil, como -iname '??? trabalho. * \. Cpp'-iname
e-name
.-iname
é a versão-name
que não diferencia maiúsculas de minúsculas e não tem diferenças no tratamento das expressões regulares. Eu sugiro tentar comandos antes de postar, seu comando falha no meu shell também.