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

14

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

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

InquilineKea
источник

Ответы:

13

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

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

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

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

jgoldschrafe
источник
2
+1, выглядит хорошо. Вы можете сделать его немного более устойчивым, используя '-' в качестве первого аргумента для mv. охранники против filenaes , начинающихся с '-'
Cas
5
Что это за dateреализация? dateКажется, мой GNU не обрабатывает ввод.
Манатворк
coreutils 8.4 на RHEL 6.
jgoldschrafe
2
@jgoldschrafe, вы уверены, что код правильно работает для вас? pastebin.com/nNYubf3A
manatwork
5
хороший улов manatwork. моя дата в GNU 8.13 также не поддерживает чтение из стандартного ввода. Он поддерживает использование времени мод файла с «-r» - например, «дата +% Y% m% d -r $ f», поэтому в этом конкретном случае даже статистика не требуется.
Cas
18

Вот версия однолинейной версии Goldschrafe, которая:

  • не использует стат
  • работает с более ранними версиями даты GNU
  • правильно справляется с любыми пробелами в именах файлов
  • также справляется с именами файлов, начинающимися с тире

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

саз
источник
1
Вы должны сделать это, date -r "$f" +%Y%m%dили это не будет работать, если POSIXLY_CORRECTнаходится в окружающей среде. Как правило, параметры должны идти перед другими аргументами.
Стефан Шазелас
это должен быть «правильный ответ»
invalidusername
Конечно, вам не нужны скобки "${f}".
G-Man говорит «Восстановить Монику»
но как бы вы сделали так, чтобы даты, которые мы добавили, например, "Ymd-filename"?
работы
2

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

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}'
Жиль "ТАК - перестань быть злым"
источник
1

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

Вы можете сохранить этот скрипт как «modif_date.sh» и сделать его исполняемым. Мы вызываем его с целевым каталогом в качестве аргумента:

modif_date.sh txt_collection

Где «txt_collection» - это имя каталога, в котором находятся все файлы, которые мы хотим переименовать.

#!/bin/sh

# Override any locale setting to get known month names
export LC_ALL=c
# First we check for the argument
if [ -z "$1" ]; then
    echo "Usage: $0 directory"
    exit 1
fi

# Here we check if the argument is an absolute or relative path. It works both ways
case "${1}" in
  /*) work_dir=${1};;
  *) work_dir=${PWD}/${1};;
esac

# We need a for loop to treat file by file inside our target directory
for i in *; do
    # If the modification date is in the same year, "ls -l" shows us the timestamp.
    # So in this case we use our current year. 
    test_year=`ls -Ggl "${work_dir}/${i}" | awk '{ print $6 }'`
    case ${test_year} in *:*) 
        modif_year=`date '+%Y'`
        ;;
    *)
        modif_year=${test_year}
        ;;
    esac
    # The month output from "ls -l" is in short names. We convert it to numbers.
    name_month=`ls -Ggl "${work_dir}/${i}" | awk '{ print $4 }'`
    case ${name_month} in
            Jan) num_month=01 ;;
            Feb) num_month=02 ;;
        Mar) num_month=03 ;;
        Apr) num_month=04 ;;
        May) num_month=05 ;;
        Jun) num_month=06 ;;
        Jul) num_month=07 ;;
        Aug) num_month=08 ;;
        Sep) num_month=09 ;;
        Oct) num_month=10 ;;
        Nov) num_month=11 ;;
        Dec) num_month=12 ;;
        *) echo "ERROR!"; exit 1 ;;
    esac
    # Here is the date we will use for each file
    modif_date=`ls -Ggl "${work_dir}/${i}" | awk '{ print $5 }'`${num_month}${modif_year}
    # And finally, here we actually rename each file to include
    # the last modification date as part of the filename.
    mv "${work_dir}/${i}" "${work_dir}/${i}-${modif_date}"
done
нацеливать
источник
1
прочитайте справочную страницу для stat (1), чтобы узнать, как вы можете уменьшить свой скрипт примерно на 3/4 ... большая часть вышесказанного - это заново изобретать колесо. в частности, stat -c% Y даст вам время изменения файла в секундах с начала эпохи (1970-01-01 00:00:00). Затем его можно использовать в качестве входных данных для даты (1) для форматирования временной метки, как требуется. см. ответ jgoldschrafe выше для примера.
Cas
@CraigSanders Достоинством является то, что этот скрипт работает под операционными системами, отличными от Linux, которые имеют другую statутилиту или вообще не имеют ее.
Жиль "ТАК - перестань быть злым"
Обратите внимание, что синтаксический анализ вывода lsне является надежным . В некоторых вариантах Unix имена пользователей и групп могут содержать пробелы, которые отбрасывают выравнивание столбцов даты.
Жиль "ТАК ... перестать быть злым"
@giles: правда, но любой разумный :-) установит GNU coreutils (и все другие инструменты GNU) в любую систему, не являющуюся Linux. Это самый простой способ получить не только хороший набор пользовательских инструментов, но и непротиворечивый набор независимо от базового ядра.
Cas
1
(Продолжение)… (5) Еще одна ошибка: предполагается, что любая дата / время, отображаемые ls как дата и время (а не дата и год), должны быть в текущем году. Это неправда. Это в последние шесть месяцев; это может быть в предыдущем году (например, с 27 сентября 2016 года по 31 декабря 2016 года в течение последних шести месяцев). (6) Риск попугая Wiki Грега (о котором @Gilles уже упоминал), имена файлов, содержащие символы новой строки и пробелы, могут привести к сбою. … (Продолжение)
G-Man говорит «Восстановить Монику»
0

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

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

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

for f in * ; do
  if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
    mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
  fi;
done
Гжегож Вежовецкий
источник
Если временные метки ваших файлов прикручены и имеют формат JPEG, возможно, вы захотите сначала исправить их с помощью данных EXIF: for f in *.jpg ; do jhead -ft "$f" ; donesource: unix.stackexchange.com/a/290755/9689
Grzegorz Wierzowiecki