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 rename
comando 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 coreutils
e desde que xargs
é fornecido por findutils
ele deve ser pelo menos tão portátil quanto find -execdir
ele 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 find
sozinho, 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_%p
em 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 -execdir
porque é 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_{} \;