Переименовываете группу файлов с отметкой даты изменения в конце имени файла?

Переименовываете группу файлов с отметкой даты изменения в конце имени файла?

Итак, скажем, у меня есть каталог с кучей файлов типа g.txt, где g.txt последний раз был изменен, скажем, 20 июня 2012 года.

Как мне переименовать все файлы (например, g.txt) и добавить в конец дату последнего изменения — 20 июня 2012 года?

решение1

Вот версия однострочной фразы Голдшрафе:

  • не использует статистику

  • работает с более ранними версиями GNU date

  • корректно обрабатывает любые пробелы в именах файлов

  • также справляется с именами файлов, начинающимися с тире

    for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done


Обновление 2021-03-20

Мой ответ на этот вопрос беспокоил меня годами (ну, только когда я вспоминаю о нем - в такие дни, как сегодня, когда он получает еще один голос), поэтому я наконец-то обновляю его. Мой первоначальный ответ выше все еще работает, но обновленный ответ ниже лучше.

НравитьсялюбойОперация пакетного переименования файлов должна быть выполнена с помощьюперл renameутилита, а не какая-то неуклюжая оболочка для цикла.

Утилита Perl rename по сути является специализированным языком сценариев, который позволяет использовать ЛЮБОЙ код Perl для переименования файлов, от простых s/search/replace/операций регулярных выражений (достаточно для большинства задач переименования) до сложных многострочных сценариев.

например

rename -n 'BEGIN {use Date::Format};
           die $! unless -f $_;
           next if (m/-\d{8}$/);
           my $ts=(stat($_))[9];
           my $dt=time2str("%Y%m%d",$ts);
           s/$/-$dt/;' *.txt

Для этого требуются только perl и Date::Formatмодуль (модуль, который настолько полезен, что его следует установить на любой системе с perl. По моему мнению, он, вместе с модулем автора Грэма Барра Date::Parse,долженбыть частью базовой библиотеки модулей Perl, но это не так, поэтому вам придется установить его с помощью cpanпакета дистрибутива, например пакета Debian libtimedate-perl).

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

или, для более сложной версии, которая помещает дату перед суффиксом файла (если таковой имеется):

rename -n 'BEGIN {use Date::Format; use File::Basename};
           die $! unless -f $_;
           my ($filename,$dirs,$suffix) = fileparse($_,qr/\.[^.]*/);
           next if (m/-\d{8}${suffix}$/);
           my $ts=(stat($_))[9];
           my $dt=time2str("%Y%m%d",$ts);
           s/${suffix}$/-${dt}${suffix}/;' *.txt

Эта версия не имеет дополнительных требований, поскольку File::Basenameмодуль был включен в качестве стандартного основного модуля Perl с тех пор, как я себя помню (как минимум десять лет, а возможно и больше).

Примечание:оба renameскрипта выше используют опцию rename -n(она же --nono) "dry-run", чтобы результаты можно было протестировать/смоделировать перед применением. Удалите -n(или замените на -vдля подробного вывода), когда вы будете уверены, что он делает то, что вам нужно.

Также обратите внимание:Как и любой другой renameскрипт Perl, он может переименовывать имена файлов, указанные в командной строке и/или из стандартного ввода. Например, чтобы переименовать все файлы .txt в текущем каталоге и всех подкаталогах:

find . -type f -iname '*.txt' -print0 | 
   rename -0 --nofullpath -n '..........'

Кстати, я использовал здесь опцию rename--nofullpath (она же -d, --filenmame, --nopath), чтобы гарантировать, что она переименует только часть имени файла из всех найденных путей к файлам. В этом конкретном случае это не нужно (потому что примеры сценариев переименования изменяют только конец имени файла), но обычно это хорошая идея, когда вы не хотите переименовывать путь и имя файла (например, сценарий переименования, например, 's/ //g'удаляющий пробелы из имен файлов, попытается удалить все пробелы в пути и в имени файла без --nofullpath, что, вероятно, приведет к сбою с ошибкой).

Окончательно:не путайте скрипт perl rename (он же File::Rename, или иногда называемый prenameв Fedora и RedHat, или perl-rename) с любой другой программой под названием rename. ТолькоЭта утилита переименования на основе Perl может переименовывать файлы, используя произвольный код Perl, как показано выше. Любая другая утилита переименования будет иметь другие возможности и другие и несовместимые параметры командной строки.

Вы можете проверить, установлен ли у вас правильный rename:

$ rename -V
/usr/bin/rename using File::Rename version 1.13, File::Rename::Options version 1.10

Исполняемый файл может называться prenameили , perl-renameили file-renameв вашей системе, поэтому попробуйте -Vиспользовать эти имена и измените приведенные выше примеры, чтобы использовать правильное имя исполняемого файла.

решение2

Быстрый и грязный однострочный Bash-код для переименования всех (подстановочных) файлов в текущем каталоге из filename.txtв filename.txt-20120620:

for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done

Я уверен, что предприимчивый фанат Bash найдет какой-нибудь крайний случай, чтобы его сломать. :)

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

решение3

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

zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'

Мы используем statвстроенный изzsh/statмодуль, иzmvфункция переименования файлов. А вот дополнительная, которая помещает дату перед расширением, если оно есть.

zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'

решение4

Вот версия однострочника cas (основанная на однострочнике goldschrafe), расширеннаяидемпотентность,

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

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

for f in * ; do
  if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
    mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
  fi;
done

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