Mengganti nama banyak file dengan stempel waktu yang diubah tanggal di akhir nama file?


14

Jadi, katakanlah, saya memiliki direktori dengan banyak file seperti g.txt, tempat g.txt terakhir diubah pada, katakanlah, 20 Juni 2012.

Bagaimana saya akan menamai ulang semua file (seperti g.txt) dengan tanggal modifikasi terakhir 20 Juni 2012 yang ditambahkan pada akhirnya?

Jawaban:


13

Bash one-liner cepat-dan-kotor untuk mengubah nama semua file (globbed) di direktori saat ini dari filename.txtke filename.txt-20120620:

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

Seorang kutu buku Bash giat akan menemukan beberapa kasus tepi untuk memecahkannya, saya yakin. :)

Jelas, ini tidak melakukan hal-hal yang diinginkan seperti memeriksa apakah file sudah memiliki sesuatu yang terlihat seperti tanggal di akhir.


2
+1, terlihat bagus. Anda dapat membuatnya sedikit lebih kuat dengan menggunakan '-' sebagai arg pertama ke mv. penjaga terhadap filena dimulai dengan '-'
cas

5
Apa jenis dateimplementasi itu? GNU saya datesepertinya tidak menangani input.
manatwork

coreutils 8.4 pada RHEL 6.
jgoldschrafe

2
@ jgoldschrafe, Anda yakin kode itu berfungsi dengan baik untuk Anda? pastebin.com/nNYubf3A
manatwork

5
manatwork tangkapan yang bagus. GNU date 8.13 saya tidak mendukung bacaan dari stdin juga. Itu mendukung menggunakan mod waktu file dengan "-r" - misalnya "date +% Y% m% d -r $ f", jadi stat bahkan tidak diperlukan dalam kasus khusus ini.
cas

18

inilah versi one-liner goldschrafe yang:

  • tidak menggunakan stat
  • bekerja dengan versi GNU versi sebelumnya
  • benar mengatasi dengan spasi di nama file
  • juga berupaya dengan nama file yang dimulai dengan tanda hubung

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


1
Anda harus membuatnya date -r "$f" +%Y%m%datau tidak akan berfungsi jika POSIXLY_CORRECTada di lingkungan. Secara umum, opsi harus diberikan sebelum argumen lain.
Stéphane Chazelas

ini harus menjadi "jawaban yang benar"
invalidusername

Tentu saja Anda tidak perlu kawat gigi di "${f}".
G-Man Mengatakan 'Reinstate Monica'

tetapi bagaimana Anda membuatnya sedemikian rupa sehingga tanggal yang kami tambahkan sebelumnya misalnya "Ymd-filename"?
timebandit

2

Zsh one-liner wajib (tidak termasuk pemuatan satu kali komponen opsional):

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

Kami menggunakan statbuiltin dari zsh/statmodul , dan zmvfungsinya untuk mengganti nama file. Dan inilah tambahan yang menempatkan tanggal sebelum ekstensi, jika ada.

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

1

Seperti yang saya mengerti kita tidak tahu sebelumnya apa tanggal modifikasi. Jadi kita perlu mendapatkannya dari setiap file, memformat output dan mengganti nama setiap file dengan cara sehingga termasuk tanggal modifikasi dalam nama file.

Anda dapat menyimpan skrip ini sebagai sesuatu seperti "modif_date.sh" dan membuatnya dapat dieksekusi. Kami memohonnya dengan direktori target sebagai argumen:

modif_date.sh txt_collection

Di mana "txt_collection" adalah nama direktori tempat kita memiliki semua file yang ingin kita ganti namanya.

#!/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
baca halaman manual untuk stat (1) untuk mengetahui bagaimana Anda dapat mengecilkan skrip Anda sekitar 3/4 ... sebagian besar di atas adalah menciptakan kembali roda. khususnya, 'stat -c% Y' akan memberi Anda waktu modifikasi file dalam detik sejak zaman (1970-01-01 00:00:00). Ini kemudian dapat digunakan sebagai input hingga tanggal (1) untuk memformat stempel waktu sesuai kebutuhan. lihat jawaban jgoldschrafe di atas untuk contoh.
cas

@CraigSanders Sisi baiknya adalah skrip ini bekerja di bawah sistem operasi selain Linux, yang memiliki statutilitas berbeda atau tidak sama sekali.
Gilles 'SO- stop being evil'

Perhatikan bahwa parsing output lstidak dapat diandalkan . Pada beberapa varian unix, nama pengguna dan grup dapat berisi spasi, yang akan menghilangkan penjajaran kolom tanggal.
Gilles 'SO- berhenti bersikap jahat'

@ giles: true, tetapi siapa pun yang masuk akal :-) akan menginstal GNU coreutils (dan semua alat GNU lainnya) pada sistem non-linux. Ini adalah cara termudah untuk mendapatkan tidak hanya seperangkat alat pengguna yang baik, tetapi juga set yang konsisten terlepas dari kernel yang mendasarinya.
cas

1
(Lanjutan) ... (5) Bug lain: bug ini mengasumsikan bahwa setiap tanggal / waktu yang ditampilkan ls sebagai tanggal dan waktu (bukan tanggal dan tahun) harus dalam tahun berjalan. Ini tidak benar. Itu dalam enam bulan terakhir; yang bisa di tahun sebelumnya (misalnya, 27-September-2016 hingga 31-Des-2016 dalam enam bulan terakhir). (6) Dengan risiko menirukan Greg's Wiki (yang sudah dikutip @Gilles), nama file yang mengandung baris baru dan spasi dapat menyebabkan ini gagal. … (Lanjutan)
G-Man Mengatakan 'Reinstate Monica'

0

Berikut ini adalah versi one-liner cas, (berdasarkan oneliner goldschrafe) yang diperluas dengan idempoten ,

yaitu diperluas ke file awalan dengan waktu tanggal dan untuk melakukan ini hanya bagi mereka yang belum memiliki awalan waktu tanggal .

Use-case: bermanfaat jika Anda menambahkan file baru ke direktori dan ingin menambahkan awalan waktu tanggal untuk file yang belum memilikinya.

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

Jika cap waktu file Anda kacau dan jpeg, Anda mungkin ingin memperbaikinya dengan data EXIF: for f in *.jpg ; do jhead -ft "$f" ; donesumber: unix.stackexchange.com/a/290755/9689
Grzegorz Wierzowiecki
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.