Script Bash para cambiar el nombre de archivos según el tamaño

Script Bash para cambiar el nombre de archivos según el tamaño

Tengo un script bash que cambia el nombre de los archivos en una carpeta según la entrada del símbolo del sistema:

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

¿Cómo puedo modificar este script para que los archivos de la carpeta cambien de nombre según su tamaño?

Si ordeno los archivos según el tamaño, se verán así en la carpeta:

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

Entonces quiero que se cambie el nombre de los archivos resultantes:

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

Respuesta1

Algo como esto:

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}

Respuesta2

El truco principal es reemplazar

    for i in *.jpg

con

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

sin embargo, como señaló Kusalananda, esto supone nombres de archivos "educados" (sin espacios, sin caracteres de control), por lo que aquí hay un enfoque diferente:

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

-Sordena disminuyendo el tamaño del archivo
--escapeevita que los nombres con nuevas líneas incrustadas causen daños
--no-clobberevita que se sobrescriban los archivos de destino en caso de que el script se ejecute dos veces

PD: La respuesta de Ole Tange es una forma muy agradable y eficiente de hacer lo mismo, pero probablemente no verá la diferencia a menos que cambie el nombre de miles de archivos de forma rutinaria.

Respuesta3

En el zshcaparazón:

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

Esto iteraría sobre todos los archivos normales con un .jpgsufijo de nombre de archivo en el directorio actual, en orden de mayor a menor. Para cada archivo, le cambiaría el nombre a aNNN.jpgdonde NNNestá el recuento entero lleno de ceros de los archivos procesados ​​hasta el momento.

El (.DNOL)calificador global ordena los nombres de archivos coincidentes en el orden correcto usando OL("orden inverso por longitud") y selecciona solo archivos normales (incluidos nombres ocultos) usando .D("archivos normales y archivos de puntos"). Esto Nhace que el patrón se expanda a nada si no hay ningún nombre coincidente ("glob nulo").

Esto funcionaría con todos los nombres de archivos válidos en cualquier sistema Unix que tenga zshinstalado.

Para usar esto desde bash:

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

Si tiene una variable $renameque desea pasar como prefijo de nombre de archivo en lugar 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"

Tenga en cuenta que zshen la última línea no es un error tipográfico y que el valor de $renamese utiliza $1dentro del zsh -cscript.

información relacionada