Скрипт Bash для переименования файлов в зависимости от размера

Скрипт Bash для переименования файлов в зависимости от размера

У меня есть bash-скрипт, который переименовывает файлы в папке в соответствии с вводом из командной строки:

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

Как изменить этот скрипт, чтобы файлы в папке переименовывались в соответствии с их размером?

Если отсортировать файлы по размеру, то в папке они будут выглядеть так:

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

Поэтому я хочу переименовать полученные файлы:

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

решение1

Что-то вроде этого:

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}

решение2

Главный трюк — заменить

    for i in *.jpg

с

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

Однако, как указал Кусалананда, это предполагает «образованные» имена файлов (без пробелов и управляющих символов), поэтому вот другой подход:

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

-Sсортировка по уменьшению размера файла
--escapeпредотвращает повреждение имен со встроенными переносами строк
--no-clobberпредотвращает перезапись целевых файлов в случае, если скрипт запускается дважды

P.S. Ответ Оле Танге — очень хороший и эффективный способ сделать то же самое, но вы, вероятно, не увидите разницы, если только не будете регулярно переименовывать тысячи файлов.

решение3

В zshоболочке:

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

Это переберет все обычные файлы с .jpgсуффиксом имени файла в текущем каталоге в порядке от наибольшего к наименьшему. Для каждого файла он переименует его в , aNNN.jpgгде NNN— заполненное нулями целое число файлов, обработанных до сих пор.

Квалификатор (.DNOL)glob упорядочивает соответствующие имена файлов в правильном порядке с помощью OL("reverse order by length") и выбирает только обычные файлы (включая скрытые имена) с помощью .D("regular files, and dot-files"). Это Nзаставляет шаблон расширяться до нуля, если нет соответствующего имени ("null glob").

Это будет работать со всеми допустимыми именами файлов в любой zshустановленной системе Unix.

Чтобы использовать это из bash:

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

Если у вас есть переменная $rename, которую вы хотите передать как префикс имени файла вместо использования 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"

Обратите внимание, что zshв последней строке не является опечаткой и что значение $renameиспользуется $1внутри zsh -cскрипта.

Связанный контент