Para cada subpasta, classifique os arquivos por nome e renomeie-os para números preenchidos sequenciais (independentemente da extensão)

5

Eu tenho a seguinte estrutura de diretórios:

.
├── event-a
│   ├── album-a
│   │   ├── a.jpg
│   │   └── x.png
│   └── album-b
│       ├── a.jpg
│       ├── x.png
│       └── y.gif
└── event-b
    ├── album-x
    │   ├── a.jpg
    │   └── x.png
    └── album-y
        ├── a.jpg
        ├── x.png
        └── y.gif

Para cada subpasta de segundo nível (denominada album-foo no exemplo), desejo classificar os arquivos por nome e renomeá-los para números preenchidos sequenciais, independentemente de sua extensão. As pastas podem conter imagens JPG, PNG ou GIF, e qualquer extensão de arquivo deve ser preservada.

Então, neste caso, gostaria de obter este resultado:

.
├── event-a
│   ├── album-a
│   │   ├── 01.jpg
│   │   └── 02.png
│   └── album-b
│       ├── 01.jpg
│       ├── 02.png
│       └── 03.gif
└── event-b
    ├── album-x
    │   ├── 01.jpg
    │   └── 02.png
    └── album-y
        ├── 01.jpg
        ├── 02.png
        └── 03.gif

O utilitário rename pode ser usado se isso facilitar alguma coisa.

O principal problema é descobrir o número que cada arquivo deve receber. Preciso usar um loop for aninhado para iterar sobre as subpastas event-x e album-x e, em seguida, para cada loop interno, controlar o número sozinho ou há alguma solução inteligente que esteja faltando? / p>     

por Mathias Bynens 23.04.2012 / 16:33

4 respostas

7
for dir in */*; do           # loop over the directories
    (                        # run in a subshell ...
        cd "$dir"            # ... so we don't have to cd back
        files=(*)            # store the filenames in a zero-indexed array

        for index in "${!files[@]}"; do
            file=${files[$index]}
            ext=${file##*.}
            newname=$(printf "%02d.%s" $((index+1)) "$ext")
            mv "$file" "$newname"
        done
    )
done

Suponha que você tenha um arquivo sem extensão. Nesse caso, terá o mesmo nome, exceto com números iniciais (por exemplo, my_file = > 05.my_file )

Todas as entradas do diretório não ocultas serão renomeadas, incluindo os diretórios.

    
por 23.04.2012 / 18:39
3

Você tem dois conjuntos de problemas aqui:

  1. Recursando em diretórios.
  2. Reiniciando o sistema de numeração em cada diretório separado.

Isso manipulará as duas condições sem problemas, embora você deseje modificar a variável IMAGE_TYPES se decidir incluir outras extensões também.

#!/bin/bash

shopt -s extglob
shopt -s nocaseglob

IMAGE_TYPES='jpg|png|gif'
IFS=$'\n' dirlist=('find "$PWD" -type d')

for dir in "${dirlist[@]}"; do
    cd "$dir"
    ls *.+($IMAGE_TYPES) > /dev/null 2>&1 || continue

    counter=0
    for file in *.+($IMAGE_TYPES); do
        printf -v newname "%.3d.%s" $((counter += 1)) "${file##*.}"
        mv --verbose "$file" "$newname"
    done
done
    
por 23.04.2012 / 20:32
0

Eu criei a mesma árvore e fiz sua jogada. Aqui está o que eu criei:

n=0 IFS=.; set -f ./[e]vent*/*/*
for f do [ -n "${f##./\[*}" ] || break
    [ "$d" = "${f%/*}" ] || i=0 d=${f%/*}
    mv=': mv "${'$((n=$n+1))'}" "${'$n'%%/*}/'
    printf "$mv%.2d%.0s.%s\"\n" $((i=$i+1)) ${f##*/}
done | sh -sx -- "$@"

Sem esse último | pipe no final, isso é o que é impresso:

mv "${1}" "${1%/*}/01.jpg"
mv "${2}" "${2%/*}/02.png"
mv "${3}" "${3%/*}/01.jpg"
mv "${4}" "${4%/*}/02.png"
mv "${5}" "${5%/*}/03.gif"
mv "${6}" "${6%/*}/01.jpg"
mv "${7}" "${7%/*}/02.png"
mv "${8}" "${8%/*}/01.jpg"
mv "${9}" "${9%/*}/02.png"
mv "${10}" "${10%/*}/03.gif"

Não parece muito, eu sei, mas o que é importante aqui é que você não precisa se preocupar com nenhum nome de arquivo estranho ou nada disso - o destino pretendido para essa saída é um shell que compartilha uma matriz posicional com o loop for que o gerou. Eu tenho um tal no comando lá - e ele está configurado para fornecer saída de depuração, que se parece com isso:

+ : mv ./event-a/album-a/a.jpg ./event-a/album-a/01.jpg
+ : mv ./event-a/album-a/x.png ./event-a/album-a/02.png
+ : mv ./event-a/album-b/a.jpg ./event-a/album-b/01.jpg
+ : mv ./event-a/album-b/x.png ./event-a/album-b/02.png
+ : mv ./event-a/album-b/y.gif ./event-a/album-b/03.gif
+ : mv ./event-b/album-x/a.jpg ./event-b/album-x/01.jpg
+ : mv ./event-b/album-x/x.png ./event-b/album-x/02.png
+ : mv ./event-b/album-y/a.jpg ./event-b/album-y/01.jpg
+ : mv ./event-b/album-y/x.png ./event-b/album-y/02.png
+ : mv ./event-b/album-y/y.gif ./event-b/album-y/03.gif

Isso é o que parece quando o : é o primeiro caractere na string de formato printf . Quando eu removê-lo e executar o comando:

ls ./event*/*/

./event-a/album-a/:
01.jpg  02.png

./event-a/album-b/:
01.jpg  02.png  03.gif

./event-b/album-x/:
01.jpg  02.png

./event-b/album-y/:
01.jpg  02.png  03.gif

Isso parece estar alinhado com sua solicitação. Você não pode bater resultados, eu acho.

    
por 27.08.2014 / 06:08
-1

Se você tiver o nome do arquivo, poderá obter seu número executando:

ls -1 <your_dir> | grep <file_name> -B 1000 | wc -l
    
por 23.04.2012 / 18:21