Anexe ao nome do arquivo com o comando find

Anexe ao nome do arquivo com o comando find

Há algum caminhoapenas com o comando findacrescentar uma string aos nomes de arquivos?

Então isso:

201a.txt
201b.png
...

Torna-se isto:

foo_201a.txt
foo_201b.png
...

Esse:

find . -name '201*' -execdir mv {} foo_{} \;

Não funciona porque a {}parte inclui o início ./do nome do arquivo e, portanto, tenta gravar em foo_./201*.

Se isso não for possível apenas com find, qual é a maneira mais portátil (leia-se: apenas coreutils, sem scripts de shell, mais fácil de entender) de acrescentar uma string aos nomes de arquivos?

Responder1

Não. Mas o renamecomando oferece uma solução simples.

$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$

Responder2

Que tal

find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}

basenameé fornecido por coreutilse desde que xargsé fornecido por findutilsele deve ser pelo menos tão portátil quanto find -execdirele próprio.


Alternativamente, usando apenas recursos de shell POSIX

find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;

Responder3

Isso não é possível findsozinho, nem mesmo com o GNU find. GNU find pode imprimir arquivos com o prefixo da linha de comando removido e outro prefixo colocado em seu lugar, usando -printf foo_%pem vez de -print, mas não há nada semelhante para -exec.

(Você poderia usar find -printf 'mv foo_%p …' | sh, se você gosta de viver perigosamente. Isso só funciona com nomes de arquivos “mansos” e quebra horrivelmente se houver espaços, aspas e outros caracteres especiais nos nomes dos arquivos. Portanto, não faça isso.)

A maneira padrão de fazer isso (como funciona em qualquer sistema POSIX, e também como de maneira comum) é chamar um shell para fazer a manipulação da string.

find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;

Não uso -execdirporque é uma extensão GNU e você pediu portabilidade. Observe que isso {}é passado para o shell como um argumento. Nunca use {}dentro do código shell: não apenas porque não é portátil, mas o mais importante, porque faria com que o nome do arquivo fosse interpretado como código shell, o que falharia se o nome do arquivo contivesse caracteres especiais.

Em sistemas POSIX modernos (qualquer coisa da última década), você pode acelerar um pouco esse comando agrupando em lote as chamadas do shell.

find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +

Alternativamente, em ksh, bash ou zsh, você pode usar globbing recursivo em vez de chamar find.

set -o globstar # ksh only
shopt -s globstar # bash only
for x in **/201*; do
  mv -- "$x" "${x%/*}/foo_${x##*/}"
done

Responder4

Você poderia usar um asterisco ( *) para remover a ./peça:

find * -name '201*' -exec mv {} foo_{} \;  

informação relacionada