find -exec: adiciona argumentos entre {} e +
Quero usar find para localizar arquivos e copiá-los para um diretório, então tentei:
find . -name '*.png' -exec cp {} /tmp/dest +
No entanto, isso falha com
find: missing argument to `-exec'
Quando substituo o +por a, ;ele funciona, mas invoca cp para cada arquivo individualmente. Como posso adicionar um argumento final (como um diretório de destino) ao usar a +forma de -exec?
Claro, neste caso eu posso contornar a limitação aparente usando cp -t(como indicado neste post no Stack Overflow , mas essa solução é específica para cp. Em vez disso, posso estar usando rsync, scp ou alguma outra ferramenta. Existe uma maneira geral de adicionar argumentos entre {}e +em find -exec?
Respostas
Não, se você estiver usando -exec ... {} +, pode haver nada entre {}e +para além do espaço em branco. Não há jeito de contornar isso.
A partir da especificação padrão POSIX do findcomando :
-exec utility_name [argument ...] ;
-exec utility_name [argument ...] {} +O final da expressão primária deve ser pontuado por a
<semicolon>ou por a<plus-sign>. Apenas um<plus-sign>que segue imediatamente um argumento contendo apenas os dois caracteres{}deve pontuar o final da expressão primária. Outros usos do<plus-sign>não devem ser tratados como especiais.
Uma solução mais genérica possivelmente seria
find ... -exec sh -c 'cp "$@" /tmp/dest' sh {} +
Aqui, um sh -cscript embutido é executado com lotes de argumentos de find. Dentro do script embutido, "$@"estará a lista de argumentos passados (citados individualmente), o que nos permite colocá-los como queremos na cplinha de comando.
Isso nos permite usar não GNU cp(por exemplo, no macOS ou em outros sistemas BSD, onde não há -topção) ou qualquer outro utilitário de onde se queira adicionar outros argumentos ao final da lista de nomes de caminho vindos find.
Relacionado:
- Compreendendo a opção -exec de `find`
Ninguém pediu isso, mas enfim ...
Com o diretório de destino em uma variável destdir:
destdir=/tmp/dest
find ... -exec sh -c 'destdir=$1; shift; cp "$@" "$destdir"' sh "$destdir" {} +
Observe que destdirna chamada do shell findé uma variável separada do destdirno sh -cscript.
Ou, com bash:
destdir=/tmp/dest
find ... -exec bash -c 'cp "${@:2}" "$1"' bash "$destdir" {} +
Isso é "fatiar" a "$@"lista para reorganizá-la apropriadamente para a cplinha de comando, sem extrair $1, o nome do caminho do diretório de destino, em uma variável separada.