Переименование файлов в папке на последовательные номера


230

Я хочу переименовать файлы в каталоге с последовательными номерами. На основании даты создания файлов.

Для примера , sadf.jpgчтобы 0001.jpg, wrjr3.jpgчтобы 0002.jpgи так далее, количество ведущих нулей в зависимости от общего количества файлов (нет необходимости в дополнительных нулей , если не требуется).


Я смотрю на stackoverflow.com/questions/880467/… , но я не могу заставить это работать на меня.
Гнут

1
Linux / Unix не хранят дату создания.
Приостановлено до дальнейшего уведомления.

1
ls -1tr | переименуйте -v 's / .*/ в наш $ i; if (! $ i) {$ i = 1;} sprintf ("% 04d.jpg", $ i ++) / e'
maXp

Ответы:


314

Попробуйте использовать цикл letи printfдля заполнения:

a=1
for i in *.jpg; do
  new=$(printf "%04d.jpg" "$a") #04 pad to length of 4
  mv -i -- "$i" "$new"
  let a=a+1
done

использование -iфлага предотвращает автоматическую перезапись существующих файлов.


4
Вы также можете сделать, printf -v new "%04d.jpg" ${a}чтобы поместить значение в переменную. И ((a++))работает, чтобы увеличить переменную. Кроме того, это не делает это в порядке даты создания и не минимизирует отступы, которые являются указанными OP. Однако следует отметить, что Linux / Unix не хранит дату создания.
Приостановлено до дальнейшего уведомления.

3
Необходимо, чтобы двойная кавычка обернула mv, чтобы это работало в моей среде bash. mv "$ {i}" "$ {new}"
Гари Томанн

2
Это может быть просто Cygwin (хотя его поведение в терминале во многом идентично обычным оболочкам Unix), но, похоже, есть проблема, когда в имени файла есть пробелы.
Geesh_SO

2
Вероятно, было бы также желательно использовать mv -- "$i" "$new"для правильной обработки исходных имен файлов, которые начинаются с тире; как он mvбудет пытаться проанализировать такие имена файлов, как коллекции флагов.
Чарльз Даффи

2
Я потерял около 800 файлов с первого взгляда. Я думаю, что -iдолжны быть включены в ответ, и примечание должно быть переписано соответственно. это будет более безопасно. :(
KrIsHnA

270

Салон в одну строчку:

ls -v | cat -n | while read n f; do mv -n "$f" "$n.ext"; done 

Вы можете изменить .extс помощью .png, .jpgи т. Д.


4
легенда :), я использовал это на git shell на windows, прекрасно работает! ^^.
Mr.K

4
Прекрасно работает. Салон в одну строчку. Я добавил ls -tr, чтобы получить файлы по времени последнего изменения.
Ранджит Сиджи

32
добавить printf вот так: ls | cat -n | while read n f; do mv "$f" `printf "%04d.extension" $n`; doneчтобы числа были дополнены нулями
Seweryn Niemiec

8
Предупреждение: вы можете добавить -nкоманду mv, чтобы предотвратить случайную перезапись файлов. Обнаружил этот трудный путь!
Ян Данфорт

4
Собираем некоторые отличные идеи из комментариев к этому ответу и другим: ls -1prt | grep -v "/$" | cat -n | while read n f; do mv -n "${f}" "$(printf "%04d" $n).${f#*.}"; done Результаты: (1) отсортированы в порядке модификации, более поздние файлы с более поздними индексами; (2) игнорирует каталоги - и не рекурсивно; (3) колодки указатели; (4) поддерживает оригинальное расширение.
Хорхе

63

Мне нравится решение Гауте за его простоту, но оно имеет важный недостаток. При работе с тысячами файлов вы можете получить сообщение «список аргументов слишком длинный» ( подробнее об этом ), а во-вторых, скрипт может работать очень медленно. В моем случае, запустив примерно 36.000 файлов, скрипт переместился на ок. один предмет в секунду! Я не совсем уверен, почему это происходит, но правило, которое я получил от коллег, было « findтвой друг» .

find -name '*.jpg' | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

Для подсчета предметов и построения команды использовался gawk . Обратите внимание на главное отличие. По умолчанию findвыполняется поиск файлов в текущем каталоге и его подкаталогах, поэтому обязательно ограничивайте поиск только в текущем каталоге, если это необходимо (используйте, man findчтобы узнать как).


7
Я изменил, чтобы использовать номер строки NRдля более короткой команды. gawk '{ printf "mv %s %04d.jpg\n", $0, NR }'
Апиват Чантавибул

12
Огромные уязвимости безопасности здесь. Подумайте, есть ли у вас файл с именем $(rm -rf /).jpg.
Чарльз Даффи

Спасибо, что указал на это, Чарльз. Можете ли вы предложить безопасное решение?
beibei2

2
ломается, если в имени файла есть пробелы. Используйте кавычки вокруг исходного имени файла. printf "mv \"% s \ "% 04d.jpg \ n", $ 0, a ++
baskin

1
forЦикл не принимает 1 секунду на файл, строго говоря. Извлечение 36 000 имен файлов из файловой системы занимает много времени, а затем проходит по ним достаточно быстро. Многие файловые системы имеют проблемы с большими каталогами, независимо от того, какие именно команды вы выполняете; но, как правило, findбудет быстрее, чем подстановочный знак оболочки, потому что он должен выбрать и отсортировать список подходящих файлов.
tripleee

30

с командой "переименовать"

rename -N 0001 -X 's/.*/$N/' *.jpg

или

rename -N 0001 's/.*/$N.jpg/' *.jpg

32
Мой rename(Linux Mint 13) не имеет -Nвозможности.
Люк H

Я могу сказать только о упоминании команды переименования, я никогда не слышал об этом
Дмитрий Королев

8
Мне интересно знать, где можно получить команду переименования с опцией -N. Моя Ubuntu 14.04 не имеет его.
Стефан Хеннингсен

1
Я люблю renameкоманду, но я никогда не знал о -N! Спасибо!
Дэн Лекок

1
Существует как минимум три разных инструмента, известных какrename . Ссылка, размещенная @Bostrot, является еще одним инструментом переименования, и похоже, что @RomanRhrnNesterov использовал его. ¶ Всем пользователям от renamePeder Stray и Larry Wall (пакет perl-renameна Arch Linux и пакет renameна Debian / Ubuntu): Вы можете определить $Nсебя:perl-rename '$N=sprintf("%04d",++$N); s/.*/$N.jpg/' *.jpg
Socowi

30

использование решения Pero на OSX потребовало некоторой модификации. Я использовал:

find . -name '*.jpg' \
| awk 'BEGIN{ a=0 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' \
| bash

примечание: для продолжения строки есть обратная косая черта

отредактируйте 20 июля 2015: включил отзыв @ klaustopher, чтобы процитировать \"%s\"аргумент mvкоманды для поддержки имен файлов с пробелами.


3
Как и решение Pero, здесь есть уязвимости в безопасности. Подумайте, есть ли у вас файл с именем $(rm -rf /).jpg.
Чарльз Даффи

Спасибо, это работает. Но вы должны процитировать первый аргумент mv. Если у вас есть файл с именем, т.е. some thing.jpgваш сценарий не работает. Вот что я использовал:find . -name '*.jpg' | awk 'BEGIN{ a=0 }{ printf "mv \"%s"\ wallpaper-%04d.jpg\n", $0, a++ }' | bash
Клаустофер

я бы, вероятно, использовал -maxdepth 1для работы только на jpgs в текущем каталоге, так как это лучше, чем потом сожалеть.
Петер Перхач

Если вы переместите символ канала в конец предыдущей строки, вам не понадобится обратная косая черта.
tripleee

Вы можете использовать ls -1 *.jpgвместо поиска, иначе он не будет отсортирован. Или добавьте |sort|перед AWK
JPT

28

Очень простой bash one liner, который сохраняет исходные расширения, добавляет лидирующие нули, а также работает в OSX:

num=0; for i in *; do mv "$i" "$(printf '%04d' $num).${i#*.}"; ((num++)); done

Упрощенная версия http://ubuntuforums.org/showthread.php?t=1355021


Именно то, что я искал. Мне нравится, что вы можете установить начальный индекс.
Джек Виал,

2
Обратите внимание, что это не сохранит первоначальный порядок файлов.
Рой Шилкрот

@RoyShilkrot Что вы подразумеваете под « не будет сохранять первоначальный порядок» ? Глобусы в оболочках bash и других posix расширяются в отсортированном порядке в зависимости от локали системы. Конечно, это не сортируется 9.extраньше 11.ext, но другие инструменты (например ls) не будут делать это тоже.
Socowi

11

Чтобы работать во всех ситуациях, поставьте \ "для файлов, в имени которых есть пробел

find . -name '*.jpg' | gawk 'BEGIN{ a=1 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' | bash

3
На самом деле не охватывает все ситуации. Имя файла, содержащее буквальные кавычки, может тривиально убежать - и, поскольку вы используете двойные кавычки, а не одинарные кавычки, такие расширения, как $(rm -rf /)все еще соблюдаются.
Чарльз Даффи

11

Если ваш renameне поддерживает -N, вы можете сделать что-то вроде этого:

ls -1 -c | xargs rename -n 's/.*/our $i; sprintf("%04d.jpg", $i++)/e'

Редактировать Чтобы начать с данного числа, вы можете использовать приведенный ниже (несколько уродливый) код, просто замените 123 на желаемое число:

ls -1 -c | xargs rename -n 's/.*/our $i; if(!$i) { $i=123; } sprintf("%04d.jpg", $i++)/e'

Это перечисляет файлы в порядке по времени создания (сначала самое новое, добавьте -rв ls для обратной сортировки), а затем отправляет этот список файлов для переименования. Rename использует Perl-код в регулярном выражении для форматирования и увеличения счетчика.

Однако, если вы имеете дело с изображениями JPEG с информацией EXIF, я бы порекомендовал exiftool

Это из документации exiftool , в разделе «Примеры переименования»

   exiftool '-FileName<CreateDate' -d %Y%m%d_%H%M%S%%-c.%%e dir

   Rename all images in "dir" according to the "CreateDate" date and time, adding a copy number with leading '-' if the file already exists ("%-c"), and
   preserving the original file extension (%e).  Note the extra '%' necessary to escape the filename codes (%c and %e) in the date format string.

Как я могу начать с определенного номера, используя rename?
Jan

6

В OSX установите скрипт переименования из Homebrew:

brew install rename

Тогда вы можете сделать это действительно смехотворно легко:

rename -e 's/.*/$N.jpg/' *.jpg

Или добавить хороший префикс:

rename -e 's/.*/photo-$N.jpg/' *.jpg

3
Это отличный сценарий, и он зависит только от Perl. brew работает только на macs, но вы можете взять его с github ( github.com/ap/rename ) и использовать в Linux или Windows.
Тим Даннер

3
это не работает для меня. Я получилGlobal symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at (user-supplied code).
Энтони Чунг

Как пользователь Mac, я рад сообщить, что приложение переименования, на которое ссылается @TimDanner, является сверхпортативным, это было так же просто, как скачать Zip-архив, поместив утилиту переименования в каталог, который должен видеть путь моего профиля bash. , и это работает прямо из коробки. Я удивлен, что это не доступно на MacPorts. Я нахожу это настолько странным, что у меня есть справочная страница BSD для Rename (2), но при запуске rename она говорит, что команда не существует. Пойди разберись.
adamlogan

2

Следуйте команде переименовать все файлы в последовательность, а также расширение в нижнем регистре

rename --counter-format 000001 --lower-case --keep-extension --expr='$_ = "$N" if @EXT' *

1

У меня была похожая проблема, и я написал сценарий оболочки по этой причине. Я решил опубликовать его, несмотря на то, что многие хорошие ответы уже были опубликованы, потому что я думаю, что это может быть полезно для кого-то. Не стесняйтесь улучшать это!

подсчитывать

@Gnutt желаемого поведения можно добиться, набрав следующее:

./numerate.sh -d <path to directory> -o modtime -L 4 -b <startnumber> -r

Если опция -rне указана, расширение будет только смоделировано (должно быть полезно для тестирования).

Опция L описывает длину целевого числа (которое будет заполнено начальными нулями), также возможно добавить префикс / суффикс с опциями -p <prefix> -s <suffix>.

Если кто-то хочет, чтобы файлы были отсортированы по номерам, прежде чем они будут пронумерованы, просто удалите эту -o modtimeопцию.



1

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

a.jpg
b.JPG
c.jpeg
d.tar.gz
e

затем ls -1crвыводит точно список выше. Затем вы можете использовать rename:

ls -1cr | xargs rename -n 's/^[^\.]*(\..*)?$/our $i; sprintf("%03d$1", $i++)/e'

какие выводы

rename(a.jpg, 000.jpg)
rename(b.JPG, 001.JPG)
rename(c.jpeg, 002.jpeg)
rename(d.tar.gz, 003.tar.gz)
Use of uninitialized value $1 in concatenation (.) or string at (eval 4) line 1.
rename(e, 004)

Предупреждение «использование неинициализированного значения […]» отображается для файлов без расширения; Вы можете игнорировать это.

Удалить -nиз renameкоманды, чтобы фактически применить переименование.

Этот ответ вдохновлен ответом Люка от апреля 2014 года . Он игнорирует требование Гнутта об установке числа начальных нулей в зависимости от общего количества файлов.


Это был самый полезный ответ для меня, в основном потому, что я хотел выполнить пробный запуск операции до ее запуска, а также потому, что я мог настроить порядок, переключившись на ls -1tUвремя создания. Также нужно было renameустановить, чего у меня не было.
антоных,

1

Опять же, используя решение Pero с небольшими изменениями, потому что findбудет проходить по дереву каталогов в порядке элементов хранятся в записях каталога. Это (в основном) будет согласованным от запуска к запуску на одном и том же компьютере и, по сути, будет «порядком создания файла / каталога», если не было удалений.

Однако в некоторых случаях вам нужно получить логический порядок, скажем, по имени, который используется в этом примере.

find -name '*.jpg' | sort -n | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command 

3
НЕ используйте это. Такое перенаправление на bash представляет собой серьезную угрозу безопасности. Что если одно из имен файлов имеет вид blahblah; rm -r * blahblah.jpg?
Xhienne

1

Отсортировано по времени, ограничено jpg, ведущими нулями и базовым именем (на случай, если вы, вероятно, захотите):

ls -t *.jpg | cat -n |                                           \
while read n f; do mv "$f" "$(printf thumb_%04d.jpg $n)"; done

(все в одной строке, без \)


В общем, многие ответы на этой странице ужасны, так что, возможно, это не заслуживает отрицательного ответа. Однако я не решаюсь высказывать все, что используется lsв сценарии.
tripleee

Я сохраняю этот ответ с отрицательной стороны, так как, возможно, хрупкий, он работал для конкретного варианта использования, который у меня был.
Вилле

1
ls -1tr | rename -vn 's/.*/our $i;if(!$i){$i=1;} sprintf("%04d.jpg", $i++)/e'

переименовать -vn - удалить n для режима выключения теста

{$ i = 1;} - контрольный стартовый номер

"% 04d.jpg" - контрольный счетчик нуля 04 и установка расширения вывода .jpg


При голосовании этого ответа используется только собственное переименование. Мой вариант использования состоял в том, чтобы заменить первые две цифры файлов числами, начинающимися с 01:rename -v -n 's/../our $i;if(!$i){$i=1;} sprintf("%02d", $i++)/e' *
minterior

1

Для меня эта комбинация ответов сработала отлично:

ls -v | gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | bash
  • ls -v помогает упорядочить 1 10 9 в правильном порядке: 1 9 10, избегая проблем с расширением имени файла с jpg JPG jpeg
  • gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }'перенумерация с 4 символами и ведущими нулями. Избегая mv, я не пытаюсь случайно перезаписать все, что уже есть, случайно набрав тот же номер.
  • bash исполняет

Помните о том, что сказал @xhienne, передача неизвестного контента в bash представляет собой угрозу безопасности. Но это было не так для меня, поскольку я использовал свои отсканированные фотографии.


0

Вы также можете использовать ls

ls *.JPG| awk 'BEGIN{ a=0 }{ printf "mv %s gopro_%04d.jpg\n", $0, a++ }' | bash

5
См. Mywiki.wooledge.org/ParsingLs , а также описания уязвимостей в других аналогично сломанных решениях.
Чарльз Даффи

1
НЕ используйте это. Такое перенаправление на bash представляет собой серьезную угрозу безопасности. Что если одно из имен файлов имеет вид blahblah; rm -r * blahblah.JPG?
Xhienne

0

Большинство других решений будут перезаписывать существующие файлы, уже названные как числа. Это особенно проблема, если запустить скрипт, добавить больше файлов и запустить скрипт снова.

Этот скрипт сначала переименовывает существующие числовые файлы:

#!/usr/bin/perl

use strict;
use warnings;

use File::Temp qw/tempfile/;

my $dir = $ARGV[0]
    or die "Please specify directory as first argument";

opendir(my $dh, $dir) or die "can't opendir $dir: $!";

# First rename any files that are already numeric
while (my @files = grep { /^[0-9]+(\..*)?$/ } readdir($dh))
{
    for my $old (@files) {
        my $ext = $old =~ /(\.[^.]+)$/ ? $1 : '';
        my ($fh, $new) = tempfile(DIR => $dir, SUFFIX => $ext);
        close $fh;
        rename "$dir/$old", $new;
    }
}

rewinddir $dh;
my $i;
while (my $file = readdir($dh))
{
    next if $file =~ /\A\.\.?\z/;
    my $ext = $file =~ /(\.[^.]+)$/ ? $1 : '';
    rename "$dir/$file", sprintf("%s/%04d%s", $dir, ++$i, $ext); 
}

0

Этот oneliner перечисляет все файлы в текущем каталоге, сортирует по метке времени создания в обратном порядке (означает, что самый старый файл находится в начале) и автоматически переименовывается с конечными нулями в соответствии с количеством файлов. Расширение файла будет сохранено.

С годами у меня обычно есть только одна папка для фотографий и фильмов на мобильных телефонах. Применив эту команду, мои фотографии и фильмы будут готовы к слайд-шоу в правильном порядке на телевизоре или в архиве.

Имейте в виду, что если у вас есть конфликт имен файлов, вы теряете файлы. Поэтому сначала переименуйте в нечто странное, temp001.jpgа затем выполните в окончательное имя файла.

DIGITS=$(ls | wc -l | xargs | wc -c | xargs); ls -tcr | cat -n | while read n f; do mv "$f" "$(printf "%0${DIGITS}d" $n).${f##*.}"; done

1
Бег lsне один, а два раза выглядит так, что этого лучше избегать, но я не изучал его подробно.
tripleee

1. Если я намеренно предлагаю oneliner, почему вы меняете его потом? Многие пользователи, такие как я, предпочитают копировать-вставлять oneliner, чтобы завершить задачу. Для других, предпочитающих копировать построчно, есть другие ответы в этой теме. 2. Первоначальным вопросом было «количество ведущих нулей в зависимости от общего количества файлов», и это делается первым ls, поэтому требуются два из них. 3. Такие команды являются однократными и не предназначены для включения в сценарии, поэтому есть причина, по которой люди предпочитают однострочники
Flavio Aiello

1
Извините, не понял, что вы думали, что это важно. Для меня способность читать код значительно превосходит возможность копировать / вставлять его в одну строку. Я не нашел среды, в которой у Bash возникла бы проблема со вставкой, занимающей несколько строк, но я могу что-то пропустить.
tripleee

0

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

Здесь я заменил пробелы, '' в имени файла на '_' для всех файлов jpg
#! / Бен / Баш
переименуйте 'y / / _ /' * jpg # замена пробелов на _
пусть х = 0;
ибо я в * .jpg; делаю
    пусть х = (х + 1)
    mv $ i $ x.jpg
сделано

Установите переименовать в Linux (Ubuntu), "sudo apt установить переименовать"
Ришанг Бхавсар

0

В настоящее время есть опция после выбора нескольких файлов для переименования (я видел в thunar file manager).

  1. выбрать несколько файлов
  2. проверить параметры
  3. выберите переименовать

Приглашение приходит со всеми файлами в этом конкретном каталоге, просто проверьте с разделом категории


-1

Этот скрипт сортирует файлы по дате создания в Mac OS Bash. Я использую его для массового переименования видео. Просто измените расширение и первую часть имени.

ls -trU *.mp4| awk 'BEGIN{ a=0 }{ printf "mv %s lecture_%03d.mp4\n", $0, a++ }' | bash

1
НЕ используйте это. Такое перенаправление на bash представляет собой серьезную угрозу безопасности. Что если одно из имен файлов имеет вид blahblah; rm -r * blahblah.mp4?
Xhienne

-1

Вот еще одно решение с командой «переименовать»:

find -name 'access.log.*.gz' | sort -Vr | rename 's/(\d+)/$1+1/ge'

Чтобы восстановить ведущие нули:rename 's/(\d+)/sprintf("%04d",$1)+1/ge'
Камиль Гудесюн

Не работает должным образом для папки, в которой есть файлы с такими именами: DSC_3451.JPG, DSC_3452.JPG и т. Д. Find -name '* .JPG' | сортировать -Vr | переименование 's / (\ d +) / $ 1 + 1 / ge' ничего не меняет
Тибериу С.

-2

Ответ Перо получил меня здесь :)

Я хотел переименовать файлы относительно времени, так как средства просмотра изображений не отображали изображения в порядке времени.

ls -tr *.jpg | # list jpegs relative to time
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

2
НЕ используйте это. Такое перенаправление на bash представляет собой серьезную угрозу безопасности. Что если одно из имен файлов имеет вид blahblah; rm -r * blahblah.jpg? Просто крайний пример.
Ксиенн


-3

Чтобы перенумеровать 6000 файлов в одной папке, вы можете использовать опцию «Переименовать» программы ACDsee.

Для определения префикса используйте этот формат: ####"*"

Затем установите начальный номер и нажмите «Переименовать», и программа переименует все 6000 файлов с последовательными номерами.


1
ОП запрашивает набор команд в Unix Bourne Shell. Вы предлагаете коммерческий продукт, который работает только в среде Windows.
Xhienne
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.