Как обнулить числа в именах файлов в Bash? - PullRequest
45 голосов
/ 11 сентября 2008

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

(foo1, foo2, ..., foo1300, ..., fooN)

С именами файлов с добавлением нуля:

(foo00001, foo00002, ..., foo01300, ..., fooN)

Ответы [ 9 ]

56 голосов
/ 30 декабря 2010

Это не чистый bash, но намного проще с командой rename:

rename 's/\d+/sprintf("%05d",$&)/e' foo*
27 голосов
/ 11 сентября 2008

В случае, если N априори не фиксировано:

 for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
18 голосов
/ 13 сентября 2010

У меня был более сложный случай, когда имена файлов имели постфикс и префикс. Мне также нужно было выполнить вычитание числа из имени файла.

Например, я хотел, чтобы foo56.png стал foo00000055.png.

Надеюсь, это поможет, если вы делаете что-то более сложное.

#!/bin/bash

prefix="foo"
postfix=".png"
targetDir="../newframes"
paddingLength=8

for file in ${prefix}[0-9]*${postfix}; do
  # strip the prefix off the file name
  postfile=${file#$prefix}
  # strip the postfix off the file name
  number=${postfile%$postfix}
  # subtract 1 from the resulting number
  i=$((number-1))
  # copy to a new name with padded zeros in a new folder
  cp ${file} "$targetDir"/$(printf $prefix%0${paddingLength}d$postfix $i)
done
5 голосов
/ 08 августа 2017

Команда oneline, которую я использую, такова:

ls * | cat -n | while read i f; do mv "$f" `printf "PATTERN" "$i"`; done

PATTERN может быть, например:

  • переименовать со счетчиком приращений: %04d.${f#*.} (сохранить оригинальное расширение файла)
  • переименование со счетчиком приращений с префиксом: photo_%04d.${f#*.} (сохранить оригинальное расширение)
  • переименовать с помощью счетчика приращений и изменить расширение на jpg: %04d.jpg
  • переименование со счетчиком приращений с префиксом и базовым именем файла: photo_$(basename $f .${f#*.})_%04d.${f#*.}
  • ...

Вы можете отфильтровать файл для переименования, например, ls *.jpg | ...

У вас есть переменная f, которая является именем файла, и i, которая является счетчиком.

На ваш вопрос правильная команда:

ls * | cat -n | while read i f; do mv "$f" `printf "foo%d05" "$i"`; done
4 голосов
/ 03 февраля 2009

Pure Bash, никаких внешних процессов, кроме 'mv':

for file in foo*; do
  newnumber='00000'${file#foo}      # get number, pack with zeros
  newnumber=${newnumber:(-5)}       # the last five characters
  mv $file foo$newnumber            # rename
done
2 голосов
/ 11 сентября 2008

Будет делать следующее:

for ((i=1; i<=N; i++)) ; do mv foo$i `printf foo%05d $i` ; done

РЕДАКТИРОВАТЬ: изменено для использования ((i = 1, ...)), спасибо mweerden !

0 голосов
/ 29 марта 2019

На номера левой панели в именах файлов:

$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 1.zzz

$ for f in [0-9]*.[a-z]*; do tmp=`echo $f | awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;

$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0001.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10

Объяснение

for f in [0-9]*.[a-z]*; do tmp=`echo $f | \
awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;
  • обратите внимание на обратные черты: `echo ... $2}\` (обратная косая черта, \, сразу над ней просто разделяет эту строку на две строки для удобства чтения)
  • в цикле найдите файлы, которые названы числами с расширениями алфавита в нижнем регистре: [0-9]*.[a-z]*
  • повторить это имя файла ($f), чтобы передать его awk
  • -F.: awk разделитель полей, точка (.): при совпадении разделяет имена файлов как два поля ($1 = число; $2 = расширение)
  • форматировать с printf: напечатать первое поле ($1, числовая часть) как 4 цифры (%04d), затем вывести период, а затем напечатать второе поле ($2: расширение) как строка (%s). Все это присваивается переменной $tmp
  • наконец, переместите исходный файл ($f) на новое имя файла ($tmp)
0 голосов
/ 26 февраля 2019

Мое решение заменяет числа, везде в строке

for f in * ; do
    number=`echo $f | sed 's/[^0-9]*//g'`
    padded=`printf "%04d" $number`
    echo $f | sed "s/${number}/${padded}/";
done

Вы можете легко попробовать его, поскольку он просто печатает преобразованные имена файлов (операции с файловой системой не выполняются).

Пояснение:

Цикл по списку файлов

Цикл: for f in * ; do ;done, перечисляет все файлы и передает каждое имя файла как переменную $f в тело цикла.

Получение номера из строки

С помощью echo $f | sed мы передаем переменную $f в sed программу.

В команде sed 's/[^0-9]*//g', часть [^0-9]* с модификатором ^ указывает на совпадение с цифрой 0-9 (не цифрой) и затем удаляет ее с пустой заменой //. Почему бы просто не удалить [a-z]? Поскольку имя файла может содержать точки, тире и т. Д. Итак, мы удаляем все, что не является числом, и получаем число.

Затем мы присваиваем результат переменной number. Не забудьте не ставить пробелы в присваивании, например number = …, потому что у вас другое поведение.

Мы присваиваем результат выполнения команды переменной, оборачивая команду символами обратной черты `.

Нулевое заполнение

Команда printf "%04d" $number изменяет формат числа на 4 цифры и добавляет нули, если наш номер содержит менее 4 цифр.

Замена числа на набранное нулями число

Мы снова используем sed с командой замены, например s/substring/replacement/. Чтобы интерпретировать наши переменные, мы используем двойные кавычки и подставляем наши переменные таким образом ${number}.


Приведенный выше скрипт просто печатает преобразованные имена, поэтому давайте выполним реальную работу по переименованию:

for f in *.js ; do
    number=`echo $f | sed 's/[^0-9]*//g'`
    padded=`printf "%04d" $number`
    new_name=`echo $f | sed "s/${number}/${padded}/"`
    mv $f $new_name;
done

Надеюсь, это кому-нибудь поможет.

Я потратил несколько часов, чтобы понять это.

0 голосов
/ 11 сентября 2008

Вот быстрое решение, которое предполагает префикс фиксированной длины (ваш "foo") и заполнение фиксированной длины. Если вам нужна большая гибкость, возможно, это будет, по крайней мере, полезной отправной точкой.

#!/bin/bash

# some test data
files="foo1
foo2
foo100
foo200
foo9999"

for f in $files; do
    prefix=`echo "$f" | cut -c 1-3`        # chars 1-3 = "foo"
    number=`echo "$f" | cut -c 4-`         # chars 4-end = the number
    printf "%s%04d\n" "$prefix" "$number"
done
...