Verifica se il file è stato modificato dopo la data in Nome file


11

Ho un file chiamato con YYYYMMDDil nome del file, ad esempio

file-name-20151002.txt

Voglio determinare se questo file è stato modificato dopo il 02-10-2015.

Appunti:

  • Posso farlo guardando l'output di ls, ma so che analizzare l'output di lsè una cattiva idea.
  • Non ho bisogno di trovare tutti i file datati dopo una data specifica, ho solo bisogno di testare un file specifico alla volta.
  • Non mi preoccupo che il file venga modificato nella stessa data dopo averlo creato. Cioè, voglio solo sapere se questo file con 20151002nel nome è stato modificato il 03 ottobre 2015 o versioni successive.
  • Sono su MacOs 10.9.5.

Ci scusiamo per non aver incluso il sistema operativo in precedenza.
Peter Grill,

Risposte:


4

Ecco alcuni modi possibili con:

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

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

Uso:

FILE più recente

Esempio di output:

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

o

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

9

Il seguente script verificherà le date di tutti i file specificati nella riga di comando:

Richiede versioni GNU di sed, dateestat

$ 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

Ecco una versione non testata, che dovrebbe funzionare su Mac (e su FreeBSD ecc.) Se ho letto correttamente le pagine man online:

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

Una soluzione ancora migliore sarebbe quella che non richiede 4-5 estensioni vs POSIX.
Thomas Dickey,

2
Sentiti libero di scrivere la tua versione, quindi. Scrivo quello che voglio scrivere, non quello che vuoi che scriva .... e questo include l'uso delle versioni GNU degli strumenti. IMO, GNU È lo standard di fatto. e il numero relativo di distro linux in uso vs non linux, non gnu * nixes lo supporta.
Cas

6
@cas: una risposta piuttosto aspra al commento di Thomas che, credo, era solo un suggerimento per migliorare la tua soluzione ... Nel mondo reale, avere lo script "il più standard possibile" non è solo un bonus, ma è necessario (o piuttosto obbligatorio). In molti posti non è possibile installare la versione GNU degli strumenti (mi capita di conoscere 3 posti diversi in cui gli ultimi vers di bash di alcuni sistemi sono 2.x e awk è così vecchio che è molto, molto vicino a quello originale). I bisogni di questa domanda non sono probabilmente "critici" (ma potrebbero essere) e spesso non sono cercati / utilizzati da altre persone, ma in generale, avere una soluzione portatile è un +
Olivier Dulac,

Sto ottenendo sed: illegal option -- rcon MacOS 10.9.5.
Peter Grill,

-rè sedun'opzione GNU per dirgli di usare espressioni regolari estese. Potresti cambiare lo script sed per usare regexp di base piuttosto che esteso (ad esempio, sed -e 's/^.*\(2015\)/\1/')ma il resto dello script probabilmente non riuscirà comunque perché richiede le versioni GNU di datee stat, e non penso che i Mac vengano con loro come standard (anche se sono disponibile per Mac in pacchetti precompilati)
cas

4

Utilizzando bash e state exprper ottenere le date come numeri e confrontandoli:

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

Questa era la mia prima risposta specifica per Linux.

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

L' =~operatore bash regexp acquisisce le 8 cifre del nome file nell'array bash BASH_REMATCH. [[ ]]confronta le stringhe, sebbene le confronti semplicemente come numeri anziché in [ -gt ].


MacOS 10.9.5 non sembra avere la -cpossibilità di farlo stat.
Peter Grill,

Colpa mia. L'equivalente sembra essere stat -f %m -t %F "$file". Mi dispiace, non posso provarlo.
Meuh

Con la modifica di statcome da tuo commento, le cose sembrano funzionare ma nessun output per tutti i casi di test. Ma cosa sta "$file" =~ ([0-9]{8}).txt$facendo?
Peter Grill,

Cerca le 8 cifre seguite da .txtalla fine del nome file. Le parentesi ()catturano la parte di 8 cifre e puoi trovarla in ${BASH_REMATCH[1]}.
Meuh

Se il tuo bash non funziona con if [[=~]]puoi provare il basic if filedate=$(expr "$file" : '.*-\([0-9]*\).txt')e poi sostituirlo ${BASH_REMATCH[1]}con $filedate.
Meuh

4

Potresti farlo:

  • estrarre i valori di anno / mese / giorno in una variabile shell,
  • creare un file temporaneo
  • utilizzare il touchcomando (aggiungendo 0s per ora / minuto / secondo) per impostare la data di modifica per il file temporaneo

Poiché la tua domanda riguarda bash, probabilmente stai usando Linux. Il testprogramma utilizzato in Linux (parte di coreutils ) ha estensioni per il confronto timestamp ( -nte -ot) non trovato in POSIXtest .

Commenti POSIX al riguardo nella logica di test:

Alcune primarie aggiuntive appena inventate o dalla KornShell sono apparse in una prima proposta come parte del comando condizionale ( [[]]): s1> s2, s1 <s2, str = pattern, str! = Pattern, f1 -nt f2, f1 -ot f2, e f1 -ef f2. Non sono stati portati avanti nell'utilità di test quando il comando condizionale è stato rimosso dalla shell perché non sono stati inclusi nell'utilità di test incorporata nelle implementazioni storiche dell'utilità sh.

Utilizzando tale estensione, è possibile quindi

  • creare un altro file temporaneo con la data con cui si desidera confrontare
  • utilizzare l' -ntoperatore testper effettuare il confronto richiesto.

Ecco un esempio Un chiarimento di OP ha menzionato la piattaforma, quindi si potrebbe usare statcome alternativa ai file temporanei (confrontare OSX e 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

Quando si creano file temporanei, è prassi normale rimuovere i file trascurati con un trapcomando.
Thomas Dickey,

Sono su MacOS 10.9.5.
Peter Grill,

Grazie per il chiarimento. I file temporanei non sono eleganti come alcuni possibili approcci basati su estensioni aggiuntive, ma fornirò un breve script di esempio, per coerenza.
Thomas Dickey,

1

Un altro zshapproccio:

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

Riporterebbe i file che hanno qualcosa che assomiglia a un timestamp nel loro nome ma che non corrisponde all'ora dell'ultima modifica.

zshha una pletora di operatori come quello per manipolare globi e variabili. È molto utile svolgere qualsiasi lavoro rapidamente (e generalmente in modo affidabile), ma è piuttosto difficile metterli tutti in testa e spesso produce ciò che normalmente chiamiamo codice di sola scrittura (eufemismo per codice illeggibile, anche se implica anche che non si ' ho bisogno di leggerlo mentre lo scrivi per un singolo utilizzo al prompt dei comandi)

Una rapida panoramica:

  • **/pattern(qualifier): glob ricorsivo con qualificatore glob.
  • [0-9](#c8)corrisponde a 8 cifre. Questo è l'equivalente di zsh extendedglob kshs' {8}([0-9]).
  • D: include file nascosti
  • e@...@: il qualificatore glob eval per eseguire del testo per qualificare ulteriormente i file. Percorso del file passato$REPLY
  • zstat...recuperare il mtime formattato come AAAAMMGG $mnell'array.
  • ${REPLY:t}: si espande nella coda t (il nome base) del file.
  • ${(SM)something#pattern}. Estrarre il modello di corrispondenza della parte da qualcosa . Quelli S( ricerca S ubstring) e M(espandi alla porzione M atched) sono chiamati flag di espansione dei parametri .
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.