Dosyanın Dosya Adında Son Tarihten Sonra Değiştirilip Değiştirilmediğini Test Edin


11

Dosya adında adlı bir dosyam var YYYYMMDD, örneğin

file-name-20151002.txt

Bu dosyanın 2015-10-02'den sonra değiştirilip değiştirilmediğini belirlemek istiyorum .

Notlar:

  • Bunu çıktısına bakarak yapabilirim ls, ama çıktısını ayrıştırmanın lskötü bir fikir olduğunu biliyorum .
  • Ben bulmak gerek yok hepsi belirli bir tarihten sonra tarihli dosyalar, sadece bir test için gereken tek bir seferde belirli bir dosya.
  • Dosyayı oluşturduktan sonra aynı tarihte değiştirilmesinden endişe etmiyorum. Yani, sadece 20151002adında olan bu dosyanın 03 Ekim 2015 veya daha sonra değiştirilip değiştirilmediğini bilmek istiyorum .
  • MacOs 10.9.5 kullanıyorum.

İşletim sistemini daha önce dahil etmediğiniz için özür dileriz.
Peter Grill

Yanıtlar:


4

İşte bazı olası yollar:

  • 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 bir tek:

    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}"
    }

Kullanımı:

daha yeni DOSYA

Örnek çıktı:

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

veya

file-name-20151126.txt : NO: mtime is 20151026

9

Aşağıdaki komut dosyası, komut satırında belirtilen tüm dosyaların tarihlerini kontrol eder:

Bu GNU sürümlerini gerektirir sed, datevestat

$ 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

İşte test edilmemiş ancak on-line man sayfalarını doğru okuduysam Mac'lerde (ve FreeBSD vb.) Çalışması gereken bir sürüm:

#! /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

Daha da iyi bir çözüm, POSIX'e karşı 4-5 uzantı gerektirmeyen bir çözüm olabilir.
Thomas Dickey

2
Kendi sürümünüzü yazmaktan çekinmeyin. Yazmak istediğimi yazıyorum, yazmamı istediğimi değil .... ve bu araçların GNU sürümlerini kullanmayı içeriyor. IMO, GNU IS fiili standart. ve linux dışı, gnu * nixes'e karşı kullanılan linux dağıtımlarının göreli sayıları bunu desteklemektedir.
cas

6
@cas: Thomas'ın yorumuna oldukça sert bir cevap, sanırım, sadece çözümünüzü geliştirmek için bir öneri ... Gerçek dünyada, "mümkün olan en standart" betiğe sahip olmak sadece bir bonus değil, aynı zamanda gereklidir (veya yerine, zorunlu). Birçok yer, araçların GNU sürümünü yükleyemez (bazı sistemlerin en son bash sürümünün 2.x olduğu ve awk o kadar eski ki orijinaline çok yakın olan 3 farklı yer biliyorum). Bu sorunun ihtiyaçları muhtemelen "kritik" değildir (ama olabilir) ve aynı zamanda diğer insanlar tarafından sık sık aranmaz / kullanılmaz, ancak genel olarak, taşınabilir bir çözüme sahip olmak +
Olivier Dulac

Ben alıyorum sed: illegal option -- rMacOS 10.9.5 ile.
Peter Grill

-rsedgenişletilmiş düzenli ifadeler kullanmasını söyleyen bir GNU seçeneğidir. Temel örneğin genişletilmiş ziyade Regexp'i (kullanmak sed komut dosyası değiştirebilecek sed -e 's/^.*\(2015\)/\1/')o GNU sürümlerini gerektirdiğinden muhtemelen hala başarısız olur ama senaryonun geri kalanını dateve statve ben Mac'ler onlar olmasına rağmen (standart olarak onlarla birlikte gelen sanmıyorum önceden derlenmiş paketlerde Mac için kullanılabilir)
cas

4

Bash ve statve tuşlarını kullanarak exprtarihleri ​​sayı olarak almak ve karşılaştırmak için:

#!/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

Bu daha önce Linux'a özgü yanıtımdı.

#!/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

Bash =~regexp operatörü, dosya adının 8 basamağını BASH_REMATCH bash dizisine kaydeder. [[ ]]dizeleri karşılaştırır, ancak yerine sayı olarak karşılaştırırsınız [ -gt ].


MacOS 10.9.5'in -cseçeneği yok gibi görünüyor stat.
Peter Grill

Benim hatam. Eşdeğer gibi görünüyor stat -f %m -t %F "$file". Üzgünüm, test edemiyorum.
meuh

Yorumunuza göre değişiklik olduğunda stat, işler yürütülüyor gibi görünüyor, ancak tüm test senaryoları için çıktı yok. Peki, ne "$file" =~ ([0-9]{8}).txt$yapıyor?
Peter Grill

.txtDosya adının sonunda 8 rakamı ve ardından rakamı arar . Parantezler ()8 basamaklı bölümü yakalar ve içinde bulabilirsiniz ${BASH_REMATCH[1]}.
meuh

İle bash çalışmıyor ise if [[=~]]size temel deneyebilirsiniz if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')ve daha sonra değiştirmek ${BASH_REMATCH[1]}yoluyla $filedate.
meuh

4

Bunu yapabilirsin:

  • yıl / ay / gün değerlerini kabuk değişkenine ayıklamak,
  • geçici bir dosya oluştur
  • touchgeçici dosya için değişiklik tarihini ayarlamak üzere (saat / dakika / saniye için 0s ekleyerek) komutunu kullanın

Sorunuz ilgili basholduğu için muhtemelen Linux kullanıyorsunuz. testLinux kullanılan programın (bir parçası coreutils ) zaman damgası karşılaştırma (uzantıları vardır -ntve -otbulunmayan) OPSIX'dekitest .

POSIX bu konuda mantıklı yorumlar test:

Yeni icat edilen veya KornShell'den gelen bazı ek primerler, koşullu komutun bir parçası olarak erken bir teklifte ortaya çıktı ( [[]]): s1> s2, s1 <s2, str = desen, str! = Desen, f1 -nt f2, f1 -ot f2, ve f1-ef f2. Koşullu komut kabuktan kaldırıldığında test yardımcı programına iletilmemiştir çünkü sh yardımcı programının tarihsel uygulamalarına yerleştirilmiş test yardımcı programına dahil edilmemiştir.

Bu uzantıyı kullanarak,

  • karşılaştırmak istediğiniz tarihle başka bir geçici dosya oluşturun
  • istediğiniz karşılaştırmayı yapmak için -ntoperatörü kullanın test.

İşte bir örnek. OP tarafından yapılan bir açıklama platformdan bahsetti, bu yüzden statgeçici dosyalara alternatif olarak kullanılabilir ( OSX ve Linux'u karşılaştırın ):

#!/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

Geçici dosyalar oluştururken, gözden kaçan dosyaları trapkomutla kaldırmak standart bir uygulamadır .
Thomas Dickey

MacOS 10.9.5 kullanıyorum.
Peter Grill

Açıklama için teşekkürler. Geçici dosyalar, ek uzantılara dayanan bazı olası yaklaşımlar kadar zarif değildir, ancak tutarlılık için kısa bir örnek komut dosyası sunacağım.
Thomas Dickey

1

Başka bir zshyaklaşım:

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 ]]'@)

Adlarında zaman damgası gibi görünen, ancak son değişiklik zamanlarına karşılık gelmeyen bir şeyi bildirir.

zshglobları ve değişkenleri manipüle etmek için çok sayıda operatöre sahiptir. Herhangi bir işi hızlı bir şekilde (ve genellikle güvenilir bir şekilde) yapmak çok kullanışlıdır, ancak kafanızı hepsinin etrafında döndürmek oldukça zordur ve genellikle sadece salt okunur kod dediğimiz şeyi (okunaksız kod için örtmece, ama aynı zamanda Komut isteminde tek bir kullanım için yazarken okumalısınız)

Hızlı bir geçiş:

  • **/pattern(qualifier): glob niteleyici ile özyinelemeli glob.
  • [0-9](#c8)8 basamakla eşleşir. Bu, ksh's'nin zsh genişletilmiş glob eşdeğeri {8}([0-9]).
  • D: gizli dosyaları dahil et
  • e@...@: eval glob niteleyicisi, dosyaları daha fazla nitelendirmek için bazı metinler çalıştırır. Dosya yolu geçti$REPLY
  • zstat...$mdizide YYYYAAGG olarak biçimlendirilmiş mtime değerini alır .
  • ${REPLY:t}: dosyanın t kuyruğuna (taban adı) genişler .
  • ${(SM)something#pattern}. Parça eşleştirme desenini bir şeyden çıkarın . Bu S( S ubstring arama) M(genişletmek M kısmı atched) olarak adlandırılır parametre genişletme bayrakları .
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.