Uji apakah File Dimodifikasi Setelah Tanggal dalam Nama File

11

Saya memiliki nama file dengan YYYYMMDDnama file, seperti

file-name-20151002.txt

Saya ingin menentukan apakah ini berkas telah dimodifikasi setelah 2015/10/02.

Catatan:

  • Saya dapat melakukan ini dengan melihat output dari ls, tetapi saya tahu bahwa mengurai output lsadalah ide yang buruk.
  • Saya tidak perlu menemukan semua file bertanggal setelah tanggal tertentu, hanya perlu menguji satu file tertentu pada suatu waktu.
  • Saya tidak khawatir tentang file yang dimodifikasi pada tanggal yang sama setelah saya membuatnya. Artinya, saya hanya ingin tahu apakah file dengan 20151002nama ini diubah pada 03 Oktober 2015 atau lebih baru.
  • Saya menggunakan MacOs 10.9.5.
Peter Grill
sumber
Permintaan maaf karena tidak termasuk OS sebelumnya.
Peter Grill

Jawaban:

4

Berikut beberapa cara yang mungkin dilakukan dengan:

  • OSX stat:

    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(stat -f "%Sm" -t "%Y%m%d" "$1")
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }
  • GNU date:

    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(date '+%Y%m%d' -r "$1")
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }
  • zsh hanya:

    zmodload zsh/stat
    newer () {
    tstamp=${1:${#1}-12:8}
    mtime=$(zstat -F '%Y%m%d' +mtime -- $1)
    [[ ${mtime} -le ${tstamp} ]] && printf '%s\n' "$1 : NO: mtime is ${mtime}" || printf '%s\n' "$1 : YES: mtime is ${mtime}"
    }

Pemakaian:

FILE baru

Contoh output:

file-name-20150909.txt : YES: mtime is 20151026

atau

file-name-20151126.txt : NO: mtime is 20151026
don_crissti
sumber
9

Script berikut akan memeriksa tanggal semua file yang ditentukan pada baris perintah:

Hal ini membutuhkan GNU versi sed, datedanstat

$ cat check-dates.sh 
#! /bin/bash

for f in "$@" ; do
  # get date portion of filename
  fdate=$(basename "$f" .txt | sed -re 's/^.*(2015)/\1/')

  # convert it to seconds since epoch + 1 day
  fsecs=$(echo $(date +%s -d "$fdate") + 86400 | bc )

  # get modified timestamp of file in secs since epoch
  ftimestamp=$(stat -c %Y "$f")

  [ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done

$ ./check-dates.sh file-name-20151002.txt 
file-name-20151002.txt has been modified after 20151002
$ ls -l file-name-20151002.txt 
-rw-rw-r-- 1 cas cas 0 Oct 26 19:21 file-name-20151002.txt

Berikut adalah versi yang belum diuji tetapi harus berfungsi pada Mac (dan pada FreeBSD dll) jika saya telah membaca halaman manual on-line dengan benar:

#! /bin/bash

for f in "$@" ; do
  # get date portion of filename
  fdate=$(basename "$f" .txt | sed -e 's/^.*\(2015\)/\1/')

  # convert it to seconds since epoch + 1 day
  fsecs=$(echo $(date -j -f %Y%m%d "$fdate" +%s) + 86400 | bc )

  # get modified timestamp of file in secs since epoch
  ftimestamp=$(stat -f %m "$f")

  [ "$ftimestamp" -gt "$fsecs" ] && echo "$f has been modified after $fdate"
done
cas
sumber
Solusi yang lebih baik adalah solusi yang tidak memerlukan 4-5 ekstensi vs POSIX.
Thomas Dickey
2
Jangan ragu untuk menulis versi Anda sendiri. Saya menulis apa yang ingin saya tulis, bukan apa yang Anda ingin saya tulis .... dan itu termasuk menggunakan alat versi GNU. IMO, GNU ADALAH standar de-facto. dan jumlah relatif distro linux yang digunakan vs non-linux, non-gnu * nixes mendukungnya.
cas
6
@cas: balasan yang agak keras terhadap komentar Thomas yang, saya percaya, hanya saran untuk meningkatkan solusi Anda ... Di dunia nyata, memiliki skrip "yang paling standar mungkin" bukan hanya bonus, tetapi diperlukan (atau melainkan, wajib). Banyak tempat tidak dapat menginstal alat versi GNU (Kebetulan saya tahu 3 tempat berbeda di mana beberapa vers terbaru dari sistem bash adalah 2.x dan awk sudah sangat tua sehingga sangat, sangat dekat dengan yang asli). Kebutuhan pertanyaan ini mungkin bukan "kritis" (tapi bisa jadi) dan juga tidak sering dicari / digunakan oleh orang lain, tetapi secara umum, memiliki solusi portabel adalah +
Olivier Dulac
Saya sed: illegal option -- rmengerti dengan MacOS 10.9.5.
Peter Grill
-radalah sedopsi GNU untuk mengatakannya menggunakan ekspresi reguler yang diperluas. Anda dapat mengubah skrip sed untuk menggunakan regexp dasar daripada diperluas (mis. sed -e 's/^.*\(2015\)/\1/')Tetapi skrip lainnya mungkin masih akan gagal karena memerlukan versi GNU datedan stat, dan saya tidak berpikir Mac datang dengan mereka sebagai standar (meskipun mereka adalah tersedia untuk Mac dalam paket yang telah dikompilasi sebelumnya)
cas
4

Menggunakan bash dan statdan expruntuk mendapatkan tanggal sebagai angka dan membandingkannya:

#!/bin/bash
for file
do  moddate=$(stat -f %m -t %F "$file") # MacOS stat
    moddate=${moddate//-/} # 20151026
    if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')
    then  if [ $moddate -gt $filedate ]
          then echo "$file: modified $moddate"
          fi
    fi
done

Ini adalah jawaban spesifik Linux saya sebelumnya.

#!/bin/bash
for file
do  moddate=$(stat -c %y "$file")
    moddate=${moddate%% *} # 2015-10-26
    moddate=${moddate//-/} # 20151026
    if [[ "$file" =~ ([0-9]{8}).txt$ ]]
    then  if [[ $moddate > ${BASH_REMATCH[1]} ]]
          then echo "$file: modified $moddate"
          fi
    fi
done

=~Operator reg bash menangkap 8 digit nama file ke dalam array bash BASH_REMATCH. [[ ]]membandingkan string, meskipun Anda hanya membandingkannya sebagai angka [ -gt ].

meuh
sumber
MacOS 10.9.5 tampaknya tidak memiliki -copsi untuk stat.
Peter Grill
Salahku. Setara tampaknya stat -f %m -t %F "$file". Maaf, saya tidak bisa mengujinya.
meuh
Dengan perubahan dalam statsesuai komentar Anda, hal-hal tampaknya berjalan tetapi tidak ada output untuk semua kasus uji. Tapi, apa yang "$file" =~ ([0-9]{8}).txt$dilakukan?
Peter Grill
Itu mencari 8 digit diikuti oleh .txtpada akhir nama file. Tanda kurung ()menangkap bagian 8 digit, dan Anda dapat menemukannya di ${BASH_REMATCH[1]}.
meuh
Jika bash Anda tidak berfungsi, if [[=~]]Anda dapat mencoba dasar if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')dan kemudian menggantinya ${BASH_REMATCH[1]}dengan $filedate.
meuh
4

Anda bisa melakukan ini:

  • ekstrak nilai tahun / bulan / hari ke dalam variabel shell,
  • buat file sementara
  • gunakan touchperintah (menambahkan 0s untuk jam / menit / detik) untuk mengatur tanggal modifikasi untuk file sementara

Karena pertanyaan Anda adalah tentang bash, Anda kemungkinan menggunakan Linux. The testprogram yang digunakan dalam Linux (bagian dari coreutils ) memiliki ekstensi untuk timestamp perbandingan ( -ntdan -ot) tidak ditemukan dalam POSIXtest .

POSIX berkomentar tentang ini dalam dasar pemikiran untuk test:

Beberapa primer tambahan yang baru ditemukan atau dari KornShell muncul dalam proposal awal sebagai bagian dari perintah kondisional ( [[]]): s1> s2, s1 <s2, str = pola, str! = Pola, f1-bukan f2, f1 -ot f2, dan f1 -ef f2. Mereka tidak dibawa maju ke utilitas uji ketika perintah kondisional dikeluarkan dari shell karena mereka belum dimasukkan dalam utilitas tes yang dibangun ke dalam implementasi historis utilitas sh.

Dengan menggunakan ekstensi itu, Anda bisa melakukannya

  • buat file sementara lainnya dengan tanggal yang ingin Anda bandingkan
  • gunakan -ntoperator testuntuk membuat perbandingan yang Anda minta.

Berikut ini sebuah contoh. Klarifikasi oleh OP menyebutkan platform tersebut, sehingga orang dapat menggunakan statsebagai alternatif untuk file sementara (bandingkan OSX dan Linux ):

#!/bin/bash
# inspect each file...

with_tempfile() {
    echo "** with temporary file $name"
    test=$MYTEMP/$name
    touch -t $date $test
    [ $name -nt $test ] && echo "...newer"
}

# alternatively (and this is system-dependent)
with_stat() {
    echo "** with stat command $name"
    stat=$(stat -t "%Y%m%d%H%M" -f "%Sm" $name)
    [ $stat -gt $date ] && echo "...newer"
}

MYTEMP=$(mktemp -d /var/tmp/isnewer.XXXXXX)
trap "rm -rf $MYTEMP" EXIT
for name in file-name-[0-9][0-9]*.txt
do
    if [ -f "$name" ];
    then
            date=${name%%.txt}
            date=${date/file-name-}
            date=${date//-/}2359
            with_tempfile $name
            with_stat $name
    fi
done
Thomas Dickey
sumber
Saat membuat file sementara, itu adalah praktik standar untuk menghapus file yang diabaikan dengan trapperintah.
Thomas Dickey
Saya menggunakan MacOS 10.9.5.
Peter Grill
Terimakasih atas klarifikasinya. File sementara tidak seanggun beberapa pendekatan yang mungkin bergantung pada ekstensi tambahan, tapi saya akan memberikan contoh skrip pendek, untuk konsistensi.
Thomas Dickey
1

zshPendekatan lain :

zmodload zsh/stat # best in ~/.zshrc or
zmodload -F zsh/stat +b:zstat # to avoid overriding an eventual
                              # system stat command.
setopt extendedglob # best in ~/.zshrc

ls -ld -- **/*[0-9](#c8)*(De@'zstat -F %Y%m%d -A m +mtime $REPLY &&
  [[ ${(SM)${REPLY:t}#[0-9](#c8)} != $m ]]'@)

Akan melaporkan file yang memiliki sesuatu yang terlihat seperti cap waktu di nama mereka tetapi tidak sesuai dengan waktu modifikasi terakhir mereka.

zshmemiliki sejumlah besar operator seperti itu untuk memanipulasi gumpalan dan variabel. Sangat mudah untuk menyelesaikan pekerjaan apa pun (dan umumnya dapat dipercaya) tetapi cukup sulit untuk menyelesaikannya dan sering kali menghasilkan apa yang biasanya kita sebut kode hanya-tulis (eufemisme untuk kode yang tidak terbaca, meskipun juga menyiratkan bahwa Anda tidak t perlu membacanya saat Anda menulisnya untuk penggunaan tunggal pada command prompt)

Jalankan cepat melalui:

  • **/pattern(qualifier): glob rekursif dengan kualifikasi glob.
  • [0-9](#c8)cocok dengan 8 digit. Itulah zsh extendedglob setara dengan ksh's {8}([0-9]).
  • D: sertakan file tersembunyi
  • e@...@: kualifikasi global eval untuk menjalankan beberapa teks untuk lebih lanjut memenuhi syarat file. Jalur file dilewatkan$REPLY
  • zstat...mengambil mtime yang diformat sebagai YYYYMMDD dalam $marray.
  • ${REPLY:t}: mengembang ke t tail (nama samaran) dari file.
  • ${(SM)something#pattern}. Ekstrak pola pencocokan bagian dari sesuatu . Mereka S( pencarian S ubstring) dan M(meluas ke porsi M ) disebut bendera ekspansi parameter .
Stéphane Chazelas
sumber