Não. Mas o comando rename
oferece uma solução simples.
$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$
Existe uma maneira com apenas o comando find para preceder uma string para nomes de arquivos?
Para que isso:
201a.txt
201b.png
...
Torna-se assim:
foo_201a.txt
foo_201b.png
...
Isto:
find . -name '201*' -execdir mv {} foo_{} \;
Não funciona porque a parte {}
inclui o% principal./
no nome do arquivo e, portanto, tenta gravar em foo_./201*
.
Se isto não for possível apenas com o find, qual é a maneira mais portátil (leia-se: somente coreutils, nenhum shell shell, mais fácil de entender) maneira de preceder uma string para nomes de arquivos?
Isso não é possível com find
sozinho, nem mesmo com o GNU find. O GNU find pode imprimir arquivos com o prefixo da linha de comando removido e outro prefixo colocado, 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 "domesticados" e quebra horrivelmente se houver espaços, aspas e outros caracteres especiais nos nomes dos arquivos. Então não faça isso .)
A maneira padrão de fazer isso (de uma maneira que funcione em qualquer sistema POSIX, e também de maneira comum) é chamar um shell para fazer a manipulação de strings.
find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;
Eu não uso -execdir
porque é uma extensão GNU e você pediu portabilidade. Note que {}
é passado para o shell como um argumento. Nunca use {}
dentro do código do shell: não apenas porque não é portátil, mas principalmente porque faria com que o nome do arquivo fosse interpretado como código shell, que falha se o nome do arquivo contiver caracteres especiais.
Nos sistemas POSIX modernos (qualquer coisa da última década), você pode agilizar um pouco esse comando agrupando as chamadas do shell.
find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +
Como alternativa, em ksh, bash ou zsh, você pode usar globalização recursiva 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
Que tal
find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}
basename
é fornecido por coreutils
e como xargs
é fornecido por findutils
, ele deve ser pelo menos tão portátil quanto find -execdir
em si.
Alternativamente, usando apenas recursos de shell POSIX
find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;
Com o GNU Parallel, é assim:
# Make an annoying dir and a couple of annoying files
mkdir '"*'" '"
touch '"*'" '"/201'"*'" '".txt
touch '"*'" '"/201'"*'" '".png
# GNU Parallel deals nicely with annoying files
find . -name '201*' | parallel mv {} {//}/foo_{/}
Você pode usar um asterisco ( *
) em vez disso, o que retira a parte ./
:
find * -name '201*' -exec mv {} foo_{} \;
Tags command-line coreutils find