Script Bash para renomear arquivos com base no tamanho

Script Bash para renomear arquivos com base no tamanho

Eu tenho um script bash que renomeia arquivos em uma pasta de acordo com a entrada de um prompt de comando:

echo "Please rename and press enter" read rename 

if [ -z "$rename" ]; then 
  printf "no caption was selected, aborting!\n"
  exit 1
fi 

printf "rename is $rename\n" count=1

for i in *.jpg; do 
  j=printf "%04d" $count
  j="$rename"$j".jpg"
  count=$((count + 1))
  mv "$i" $j
done  
fi 
shift 
done

Como posso modificar este script para que os arquivos da pasta sejam renomeados de acordo com seu tamanho?

Se eu classificar os arquivos de acordo com o tamanho, eles ficarão assim na pasta:

a009      978kb
a001      567kb
a003      499kb
a008      432kb

Então, quero que os arquivos resultantes sejam renomeados:

a001      978kb
a002      567kb
a003      499kb
a004      432kb

Responder1

Algo assim:

echo "Please rename and press enter"
read rename 

ls |
  # prepend filename with file size in bytes
  parallel stat -c %s,,sep,,%n --  |
  # sort by number
  sort -n |
  # rename to sequencenumber followed by size in bytes
  parallel -q --colsep ,,sep,, mv {2} "$rename"{#}_{1}

Responder2

O truque principal é substituir

    for i in *.jpg

com

    for i in $(ls -S *.jpg)

no entanto, como apontou Kusalananda, isso pressupõe nomes de arquivos "educados" (sem espaços, sem caracteres de controle), então aqui está uma abordagem diferente:

count=1
ls -S --escape *.jpg | while read f; do
    n=$(printf "%04d" $count)
    ((count++))
    mv --no-clobber "$f" "$rename$n.jpg"
done

-Sclassifica diminuindo o tamanho do arquivo
--escapeevita que nomes com novas linhas incorporadas causem danos
--no-clobberevita a substituição dos arquivos de destino caso o script seja executado duas vezes

A resposta de PS Ole Tange é uma maneira muito eficiente de fazer o mesmo, mas você provavelmente não verá a diferença, a menos que renomeie rotineiramente milhares de arquivos.

Responder3

Na zshcasca:

typeset -Z 3 count=0
for name in *.jpg(.DNOL); do
    count=$(( count + 1 ))
    mv -i -- "$name" "a$count.jpg"
done

Isso iteraria todos os arquivos regulares com um .jpgsufixo de nome de arquivo no diretório atual, na ordem do maior para o menor. Para cada arquivo, ele seria renomeado para aNNN.jpgonde NNNestá a contagem inteira preenchida com zero de arquivos processados ​​até o momento.

O (.DNOL)qualificador glob ordena os nomes de arquivos correspondentes na ordem correta usando OL("inverte a ordem por comprimento") e seleciona apenas arquivos regulares (incluindo nomes ocultos) usando .D("arquivos regulares e arquivos de ponto"). Isso Nfaz com que o padrão se expanda para nada se não houver um nome correspondente ("null glob").

Isso funcionaria em todos os nomes de arquivos válidos em qualquer sistema Unix zshinstalado.

Para usar isso de bash:

zsh -c 'typeset -Z 3 count=0
for name in *.jpg(.DNOL); do
    count=$(( count + 1 ))
    mv -i -- "$name" "a$count.jpg"
done'

Se você tiver uma variável $renameque deseja passar como prefixo de nome de arquivo em vez de usar a:

zsh -c 'typeset -Z 3 count=0
for name in *.jpg(.DNOL); do
    count=$(( count + 1 ))
    mv -i -- "$name" "$1$count.jpg"
done' zsh "$rename"

Observe que a zshúltima linha não é um erro de digitação e que o valor de $renameé usado como $1dentro do zsh -cscript.

informação relacionada