Batch renomeia arquivos com nomes desconhecidos e extensões desconhecidas

3

Eu tenho várias fotos, algumas são .jpg , outras são .png . qualquer imagem pode ter um nome totalmente aleatório (possivelmente incluindo espaços). em qualquer diretório dado, como posso renomear todos eles, mantendo a extensão como está? a entrada, por exemplo:

001.jpg
02.png
05.png
zzzz.jpg

Eu gostaria de substituir completamente seus nomes por números de quatro dígitos, começando com 0001 e indo até 9999 (se necessário). assim, a saída pode parecer com:

0001.jpg
0002.png
0003.png
0004.jpg

a ordem desses arquivos é importante para mim, mas eles já estão em ordem seqüencial se eu os ordenasse apenas pelo nome do arquivo.

Eu verifiquei o perl rename e seu uso é um mistério para mim neste exemplo.

    
por azaqiel 02.08.2013 / 07:36

3 respostas

4

Solução Perl

perl -e '
    @files = sort glob "*.png *.jpg";
    for(@files){ 
        ($extension = $_) =~ s/.*\.(.*)/$1/;
        $new_name = sprintf("%04d",++$counter).".$extension";
        die "File $new_name already exists and would be clobbered\n" if -e $new_name;
        rename $_ => sprintf("%04d",++$counter).".$extension"
     }'

Solução de bash

export COUNT=0 
find . -maxdepth 1 -name "*.jpg" -o -name "*.png" -print0 | xargs -0 sort | while read file do\
extension=${file##*.}\
COUNT=$((COUNT+1))\
mv -- "$file" $(printf "%04d" $COUNT).$extension\
done

Nota

  • Ambas as soluções são A solução Bash não foi testada: tente elas em arquivos falsos primeiro.
  • A solução Bash pode quebrar se você tiver nomes de arquivos com novas linhas neles.
  • Perigo: Como apontado por Gilles nos comentários abaixo, se um dos arquivos originais tiver um nome que segue a convenção de nomenclatura de destino, ele será, na melhor das hipóteses, renomeado para outro "número" e na pior das hipóteses espancado por outro arquivo. Qual deles acontece vai depender de como ele se classifica em relação a outros arquivos. Eu adicionei uma provisão para isso na solução Perl, já que esta é a que o OP parece favorecer.
  • A solução Perl (com a disposição do ponto acima implementado) é não idempotente .
por 02.08.2013 / 13:28
2

( bash solution)

Usando printf para formatar os novos nomes e awk para escolher a extensão do nome do arquivo ...

$ ls
a.b  c.d  e.f  g.h  i.j  k.l  m.n  o.p  q.r  s.t  this file.y  u.v  w.x
$ COUNTER=0
$ for i in *; do COUNTER=$(($COUNTER + 1)); mv -v "$i" $(printf "%04g" $COUNTER).$(echo $i | awk -F'.' '{print $NF}'); done
'a.b' -> '0001.b'
'c.d' -> '0002.d'
'e.f' -> '0003.f'
'g.h' -> '0004.h'
'i.j' -> '0005.j'
'k.l' -> '0006.l'
'm.n' -> '0007.n'
'o.p' -> '0008.p'
'q.r' -> '0009.r'
's.t' -> '0010.t'
'this file.y' -> '0011.y'
'u.v' -> '0012.v'
'w.x' -> '0013.x'

Lembre-se de colocar a entrada $i entre aspas para escapar de espaços em nomes de arquivos, como você mencionou.

    
por 02.08.2013 / 08:33
0

Salve este script:

#!/bin/bash

NUM=0
NUMBER_LENGTH=4

cd $1;

ls . -1 | sort | while read file; do
    NUM=$(( $NUM + 1 ));
    PREFIX=$NUM;
    while [ ${#PREFIX} != $NUMBER_LENGTH ]; do
        PREFIX="0${PREFIX}";
    done;
    NEW_NAME=$PREFIX.'echo $file | sed 's|[^.]\+\.\([\A-Za-z0-9]\+\)||g'';
    mv "$file" "$NEW_NAME";
done

e execute-o como:

./_scriptname_ _dirWhereYourStuffIs_

CAVEAT: não coloque o script no mesmo diretório em que suas coisas estão, porque o script em si seria renomeado.

Se você é louco o suficiente, você pode fazer tudo em uma linha (sem usar o script):

NUM=0; NUMBER_LENGTH=4; ls . -1 | sort | while read file; do NUM=$(( $NUM + 1 )); PREFIX=$NUM; while [ ${#PREFIX} != $NUMBER_LENGTH ]; do PREFIX="0${PREFIX}"; done; NEW_NAME=$PREFIX.'echo $file | sed 's|[^.]\+\.\([\A-Za-z0-9]\+\)||g''; mv "$file" "$NEW_NAME"; done

CAVEAT # 2: para esta linha única, suponho que você esteja usando BASH

    
por 02.08.2013 / 08:05

Tags