Перейменування купи файлів із часовою позначкою, зміненою датою в кінці імені файлу?


14

Так, скажімо, у мене є каталог з купою файлів на зразок g.txt, де g.txt востаннє змінено, скажімо, 20 червня 2012 року.

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

Відповіді:


13

Швидкий і брудний Bash один вкладиш перейменувати всі файли (globbed) в поточному каталозі від filename.txtдо filename.txt-20120620:

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

Заповзятливий ботанік Баша знайде певний край, щоб його зламати, я впевнений. :)

Очевидно, що це не робить бажаних речей, таких як перевірка того, чи у файлі вже є щось, схоже на дату в кінці.


2
+1, добре виглядає. ви можете зробити його трохи більш надійним, використовуючи '-' як перший аргумент mv. охороняє файли, що починаються з '-'
cas

5
Що це за dateреалізація? Моя GNU date, здається, не обробляє введення.
манатура

coreutils 8.4 на RHEL 6.
jgoldschrafe

2
@jgoldschrafe, ви впевнені, що код правильно працює для вас? pastebin.com/nNYubf3A
манатурка

5
хороший маневр улову. моя дата GNU 8.13 також не підтримує читання з stdin. Він підтримує використання модного часу файлу з "-r" - наприклад, "дата +% Y% m% d -r $ f", тому stat в цьому конкретному випадку навіть не потрібен.
cas

18

Ось версія однолінійки Goldschrafe, що:

  • не використовує stat
  • працює з більш ранніми версіями дати GNU
  • правильно справляється з будь-якими пробілами у назви файлів
  • також справляється з назви файлів, починаючи з тире

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


1
Ви повинні зробити це date -r "$f" +%Y%m%dабо він не спрацює, якщо POSIXLY_CORRECTзнаходиться в навколишньому середовищі. Як правило, варіанти повинні йти перед іншими аргументами.
Stéphane Chazelas

це має бути "правильна відповідь"
недійсне ім'я користувача

Звичайно, вам не потрібні брекети "${f}".
G-Man каже: "Відновіть Моніку"

але як би ви зробили це таким, щоб дати, які ми передбачили, наприклад, "Ymd-ім'я файлу"?
timebandit

2

Обов'язковий однолінійний 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}'

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
прочитайте сторінку man для 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) у будь-яку нелінукс-систему. Це найпростіший спосіб отримати не тільки хороший набір інструментів userland, але і послідовний набір незалежно від базового ядра.
cas

1
(Продовження)… (5) Ще одна помилка: вона передбачає, що будь-яка дата / час, відображені ls як дата та час (а не дата та рік), повинні бути у поточному році. Це не правда. Це за останні півроку; що може бути в попередньому році (наприклад, з 27 вересня по 31 грудня 2016 року є протягом останніх шести місяців). (6) Загрожуючи папугою Вікі Грега (який @Gilles вже цитував), назви файлів, які містять нові рядки та пробіли, можуть призвести до цього невдачі. … (Продовження)
G-Man каже: «Відновити Моніку»

0

Ось версія Oneliner КАН ( на основі Oneliner goldschrafe в) розширено ідемпотентності ,

тобто поширюється на префіксні файли з датою і робити це лише для тих, хто ще не має префікса часу .

Use-case: корисно, якщо ви додаєте нові файли в каталог і хочете додати префікс часу дати до тих, у яких ще немає.

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

Якщо часові позначки ваших файлів накручені і є jpegs, ви, можливо, захочете, щоб фікси виправили їх за допомогою даних EXIF: for f in *.jpg ; do jhead -ft "$f" ; doneджерело: unix.stackexchange.com/a/290755/9689
Grzegorz Wierzowiecki
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.