Testen Sie, ob die Datei nach dem Datum im Dateinamen geändert wurde

11

Ich habe eine Datei mit YYYYMMDDdem Namen im Dateinamen, wie z

file-name-20151002.txt

Ich möchte feststellen, ob diese Datei nach dem 02.10.2015 geändert wurde.

Anmerkungen:

  • Ich kann dies tun, indem ich mir die Ausgabe von lsansehe, aber ich weiß, dass das Parsen der Ausgabe von lseine schlechte Idee ist.
  • Ich muss nicht alle Dateien finden , die nach einem bestimmten Datum datiert sind, sondern muss jeweils nur eine bestimmte Datei testen .
  • Ich bin nicht besorgt darüber, dass die Datei am selben Datum geändert wird, nachdem ich sie erstellt habe. Das heißt, ich möchte nur wissen, ob diese Datei mit 20151002dem Namen am 03. Oktober 2015 oder später geändert wurde.
  • Ich bin auf MacOs 10.9.5.
Peter Grill
quelle
Entschuldigung, dass Sie das Betriebssystem nicht früher aufgenommen haben.
Peter Grill

Antworten:

4

Hier sind einige Möglichkeiten mit:

  • 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 nur:

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

Verwendung:

neuere DATEI

Beispielausgabe:

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

oder

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

Das folgende Skript überprüft die Daten aller in der Befehlszeile angegebenen Dateien:

Es erfordert GNU - Versionen sed, dateundstat

$ 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

Hier ist eine Version, die nicht getestet wurde, aber auf Macs (und unter FreeBSD usw.) funktionieren sollte, wenn ich die Online-Manpages richtig gelesen habe:

#! /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
quelle
Eine noch bessere Lösung wäre eine, die keine 4-5 Erweiterungen gegenüber POSIX erfordert.
Thomas Dickey
2
Dann können Sie gerne Ihre eigene Version schreiben. Ich schreibe, was ich schreiben möchte, nicht, was ich schreiben soll ... und dazu gehört auch die Verwendung von GNU-Versionen von Tools. IMO, GNU IST der de-facto - Standard. und die relative Anzahl der verwendeten Linux-Distributionen im Vergleich zu Nicht-Linux- und Nicht-Gnu * -Nixen unterstützt dies.
Cas
6
@cas: Eine ziemlich harte Antwort auf Thomas 'Kommentar, der meines Erachtens nur ein Vorschlag zur Verbesserung Ihrer Lösung war ... In der realen Welt ist ein "möglichst standardmäßiges" Skript nicht nur ein Bonus, sondern notwendig (oder) eher obligatorisch). Viele Orte können die GNU-Version von Tools nicht installieren (ich kenne zufällig 3 verschiedene Orte, an denen die neuesten Bash-Versionen einiger Systeme 2.x sind und awk so alt ist, dass es dem Original sehr, sehr nahe kommt). Die Bedürfnisse dieser Frage sind wahrscheinlich nicht "kritisch" (könnten es aber sein) und werden auch nicht oft von anderen Menschen gesucht / verwendet, aber im Allgemeinen ist eine tragbare Lösung ein +
Olivier Dulac
Ich sed: illegal option -- rbekomme mit MacOS 10.9.5.
Peter Grill
-rist eine GNU- sedOption, mit der angewiesen wird, erweiterte reguläre Ausdrücke zu verwenden. Sie könnten das sed-Skript so ändern, dass es einen einfachen regulären Ausdruck anstelle eines erweiterten Skripts verwendet (z. B. sed -e 's/^.*\(2015\)/\1/')aber der Rest des Skripts wird wahrscheinlich immer noch fehlschlagen, da die GNU-Versionen von dateund erforderlich sind stat, und ich glaube nicht, dass Macs standardmäßig mit ihnen geliefert werden (obwohl dies der Fall ist) verfügbar für Mac in vorkompilierten Paketen)
cas
4

Verwenden Sie bash und statund expr, um die Daten als Zahlen abzurufen und zu vergleichen:

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

Dies war meine frühere Linux-spezifische Antwort.

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

Der Bash- =~Regexp-Operator erfasst die 8 Ziffern des Dateinamens im Bash-Array BASH_REMATCH. [[ ]]vergleicht die Zeichenfolgen, obwohl Sie sie stattdessen einfach als Zahlen in vergleichen [ -gt ].

meuh
quelle
MacOS 10.9.5 scheint nicht die -cOption dazu zu haben stat.
Peter Grill
Mein Fehler. Das Äquivalent scheint zu sein stat -f %m -t %F "$file". Entschuldigung, ich kann es nicht testen.
Meuh
Mit der Änderung in der statgemäß Ihrem Kommentar scheinen die Dinge ausgeführt zu werden, aber keine Ausgabe für alle Testfälle. Aber was macht das "$file" =~ ([0-9]{8}).txt$?
Peter Grill
Es sucht nach den 8 Ziffern, gefolgt vom .txtEnde des Dateinamens. Die Klammern ()erfassen den 8-stelligen Teil und finden ihn in ${BASH_REMATCH[1]}.
Meuh
Wenn Ihr bash funktioniert nicht mit if [[=~]]Ihnen kann den Grund versuchen if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')und ersetzen Sie dann ${BASH_REMATCH[1]}durch $filedate.
Meuh
4

Sie könnten dies tun:

  • Extrahieren Sie die Werte für Jahr / Monat / Tag in eine Shell-Variable.
  • Erstellen Sie eine temporäre Datei
  • Verwenden Sie den touchBefehl (Hinzufügen von 0 für Stunde / Minute / Sekunde), um das Änderungsdatum für die temporäre Datei festzulegen

Da es sich bei Ihrer Frage um handelt bash, verwenden Sie wahrscheinlich Linux. Das testunter Linux verwendete Programm (Teil von coreutils ) verfügt über Erweiterungen für den Zeitstempelvergleich ( -ntund -ot), die in POSIXtest nicht gefunden wurden .

POSIX kommentiert dies in der Begründung für test:

Einige zusätzliche neu erfundene oder aus der KornShell stammende Primärfarben erschienen in einem frühen Vorschlag als Teil des bedingten Befehls ( [[]]): s1> s2, s1 <s2, str = Muster, str! = Muster, f1 -nt f2, f1 -ot f2, und f1 -ef f2. Sie wurden nicht in das Testdienstprogramm übertragen, als der bedingte Befehl aus der Shell entfernt wurde, da sie nicht in das Testdienstprogramm aufgenommen wurden, das in historischen Implementierungen des Dienstprogramms sh integriert ist.

Mit dieser Erweiterung könnten Sie dann

  • Erstellen Sie eine weitere temporäre Datei mit dem Datum, mit dem Sie vergleichen möchten
  • Verwenden Sie den -ntOperator in test, um den gewünschten Vergleich durchzuführen.

Hier ist ein Beispiel. Eine Klarstellung von OP erwähnte die Plattform, so dass man sie statals Alternative zu temporären Dateien verwenden könnte (vergleiche OSX und 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
quelle
Beim Erstellen temporärer Dateien ist es üblich, übersehene Dateien mit einem trapBefehl zu entfernen .
Thomas Dickey
Ich bin auf MacOS 10.9.5.
Peter Grill
Danke für die Klarstellung. Temporäre Dateien sind nicht so elegant wie einige mögliche Ansätze, die auf zusätzlichen Erweiterungen beruhen. Aus Konsistenzgründen werde ich jedoch ein kurzes Beispielskript bereitstellen.
Thomas Dickey
1

Ein anderer zshAnsatz:

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

Würde die Dateien melden, deren Name wie ein Zeitstempel aussieht, der aber nicht ihrer letzten Änderungszeit entspricht.

zshhat eine Vielzahl solcher Operatoren, um Globs und Variablen zu manipulieren. Es ist sehr praktisch, um jede Arbeit schnell (und im Allgemeinen zuverlässig) zu erledigen, aber es ist ziemlich schwierig, sich mit allen vertraut zu machen, und es wird häufig das erzeugt, was wir normalerweise als schreibgeschützten Code bezeichnen (Euphemismus für unleserlichen Code, impliziert aber auch, dass Sie dies nicht tun). Sie müssen es nicht lesen, während Sie es für eine einzelne Verwendung an der Eingabeaufforderung schreiben.

Ein kurzer Durchlauf:

  • **/pattern(qualifier): rekursiver Glob mit Glob-Qualifier.
  • [0-9](#c8)entspricht 8 Ziffern. Das ist das zsh Extendedglob-Äquivalent von ksh's {8}([0-9]).
  • D: versteckte Dateien einschließen
  • e@...@: das eval glob-Qualifikationsmerkmal, um Text auszuführen und Dateien weiter zu qualifizieren. Dateipfad übergeben$REPLY
  • zstat...Rufen Sie die im $mArray als JJJJMMTT formatierte Zeit ab .
  • ${REPLY:t}: Erweitert sich zum t -Ende (dem Basisnamen) der Datei.
  • ${(SM)something#pattern}. Extrahieren des Teils passenden Muster von etwas . Diejenigen S( S ubstring Suche) und M( erweitern , um M atched Teil) werden als Parameter Expansion Flags .
Stéphane Chazelas
quelle