Prefixo ao nome do arquivo com o comando find

5

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?

    
por iquoth 12.04.2017 / 19:52

5 respostas

2

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
$
    
por 12.04.2017 / 20:40
2

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
    
por 13.04.2017 / 01:46
1

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 {} \;
    
por 12.04.2017 / 20:56
1

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_{/}
    
por 13.04.2017 / 22:22
0

Você pode usar um asterisco ( * ) em vez disso, o que retira a parte ./ :

find * -name '201*' -exec mv {} foo_{} \;  
    
por 12.04.2017 / 21:44