Как обнулить номера в именах файлов в Bash?
Вопрос
Как лучше всего с помощью Bash переименовать файлы в форме:
(foo1, foo2, ..., foo1300, ..., fooN)
С именами файлов, дополненными нулями:
(foo00001, foo00002, ..., foo01300, ..., fooN)
Решение
В случае N
не является априорно фиксированным:
for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
Другие советы
Это не чистый bash, но гораздо проще с rename
команда:
rename 's/\d+/sprintf("%05d",$&)/e' foo*
У меня был более сложный случай, когда имена файлов имели не только префикс, но и постфикс.Мне также нужно было выполнить вычитание числа из имени файла.
Например, я хотел 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
Однострочная команда, которую я использую, такова:
ls * | cat -n | while read i f; do mv "$f" `printf "PATTERN" "$i"`; done
ШАБЛОН может быть, например:
- переименовать со счетчиком приращения:
%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
Чистый 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
Это сделают следующие действия:
for ((i=1; i<=N; i++)) ; do mv foo$i `printf foo%05d $i` ; done
РЕДАКТИРОВАТЬ: изменен на использование ((i=1,...)), спасибо Мвеерден!
Вот быстрое решение, которое предполагает префикс фиксированной длины (ваш «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
Мое решение заменяет числа, везде в строке
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
Надеюсь, это кому-то поможет.
Я потратил несколько часов, чтобы разобраться в этом.
Для ввода цифр в именах файлов слева:
$ 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
)