Tester si le fichier a été modifié après la date dans le nom de fichier

11

J'ai un fichier nommé avec YYYYMMDDdans le nom de fichier, tel que

file-name-20151002.txt

Je veux déterminer si ce fichier a été modifié après le 2015-10-02.

Remarques:

  • Je peux le faire en regardant la sortie de ls, mais je sais que l'analyse de la sortie de lsest une mauvaise idée.
  • Je n'ai pas besoin de trouver tous les fichiers datés après une date spécifique, il suffit de tester un fichier spécifique à la fois.
  • Je ne suis pas préoccupé par la modification du fichier à la même date après sa création. Autrement dit, je veux juste savoir si ce fichier avec 20151002le nom a été modifié le 3 octobre 2015 ou plus tard.
  • Je suis sur MacOs 10.9.5.
Peter Grill
la source
Toutes mes excuses pour ne pas avoir inclus le système d'exploitation plus tôt.
Peter Grill

Réponses:

4

Voici quelques façons possibles avec:

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

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

Usage:

FICHIER plus récent

Exemple de sortie:

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

ou

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

Le script suivant vérifiera les dates de tous les fichiers spécifiés sur la ligne de commande:

Il nécessite des versions GNU de sed, dateetstat

$ 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

Voici une version qui n'a pas été testée mais qui devrait fonctionner sur Mac (et sur FreeBSD, etc.) si j'ai lu correctement les pages de manuel en ligne:

#! /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
la source
Une solution encore meilleure serait celle qui ne nécessite pas 4 à 5 extensions par rapport à POSIX.
Thomas Dickey
2
N'hésitez donc pas à écrire votre propre version. J'écris ce que je veux écrire, pas ce que vous voulez que j'écrive ... et cela inclut l'utilisation des versions GNU des outils. OMI, GNU EST la norme de facto. et le nombre relatif de distributions linux utilisées vs non-linux, non-gnu * nixes le supporte.
cas
6
@cas: une réponse assez dure au commentaire de Thomas qui n'était, je crois, qu'une suggestion pour améliorer votre solution ... Dans le monde réel, avoir le script "le plus standard possible" n'est pas seulement un bonus, mais est nécessaire (ou plutôt obligatoire). De nombreux endroits ne peuvent pas installer la version GNU des outils (il se trouve que je connais 3 endroits différents où la dernière version de bash de certains systèmes est 2.x et awk est si vieux qu'il est très, très proche de l'original). Les besoins de cette question ne sont probablement pas "critiques" (mais pourraient l'être) et ne sont pas souvent recherchés / utilisés par d'autres personnes, mais en général, avoir une solution portable est un +
Olivier Dulac
Je reçois sed: illegal option -- ravec MacOS 10.9.5.
Peter Grill
-rest une sedoption GNU pour lui dire d'utiliser des expressions régulières étendues. Vous pouvez changer le script sed pour utiliser une expression rationnelle de base plutôt que étendue (par exemple, sed -e 's/^.*\(2015\)/\1/')mais le reste du script échouera probablement encore car il nécessite les versions GNU de dateet stat, et je ne pense pas que les Mac les accompagnent en standard (bien qu'ils soient disponible pour Mac dans des packages pré-compilés)
cas
4

Utiliser bash et statet exprpour obtenir les dates sous forme de nombres et les comparer:

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

C'était ma réponse précédente spécifique à 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' =~opérateur d'expression rationnelle bash capture les 8 chiffres du nom de fichier dans le tableau bash BASH_REMATCH. [[ ]]compare les chaînes, bien que vous les compariez simplement sous forme de nombres à la place [ -gt ].

meuh
la source
MacOS 10.9.5 ne semble pas en avoir la -cpossibilité stat.
Peter Grill
Ma faute. L'équivalent semble être stat -f %m -t %F "$file". Désolé, je ne peux pas le tester.
meuh
Avec le changement statde selon votre commentaire, les choses semblent s'exécuter mais pas de sortie pour tous les cas de test. Mais que "$file" =~ ([0-9]{8}).txt$fait-on?
Peter Grill
Il recherche les 8 chiffres suivis de .txtla fin du nom de fichier. Les parenthèses ()capturent la partie à 8 chiffres, et vous pouvez la trouver dans ${BASH_REMATCH[1]}.
meuh
Si votre bash ne fonctionne pas, if [[=~]]vous pouvez essayer le basique if filedate=$(expr "$file" : '.*-\([0-9]*\).txt'), puis le remplacer ${BASH_REMATCH[1]}par $filedate.
meuh
4

Vous pouvez faire ceci:

  • extraire les valeurs année / mois / jour dans une variable shell,
  • créer un fichier temporaire
  • utilisez la touchcommande (en ajoutant 0 pour heure / minute / seconde) pour définir la date de modification du fichier temporaire

Parce que votre question concerne bash, vous utilisez probablement Linux. Le testprogramme utilisé sous Linux (partie de coreutils ) a des extensions pour la comparaison d'horodatage ( -ntet -ot) non trouvées dans POSIXtest .

POSIX commente ceci dans la justification de test:

Quelques primaires supplémentaires nouvellement inventées ou de KornShell sont apparues dans une première proposition dans le cadre de la commande conditionnelle ( [[]]): s1> s2, s1 <s2, str = pattern, str! = Pattern, f1 -nt f2, f1 -ot f2, et f1 -ef f2. Ils n'ont pas été reportés dans l'utilitaire de test lorsque la commande conditionnelle a été supprimée du shell car ils n'ont pas été inclus dans l'utilitaire de test intégré aux implémentations historiques de l'utilitaire sh.

En utilisant cette extension, vous pourriez alors

  • créer un autre fichier temporaire avec la date à laquelle vous souhaitez comparer
  • utilisez l' -ntopérateur testpour effectuer la comparaison que vous avez demandée.

Voici un exemple. Une clarification par OP a mentionné la plate-forme, donc on pourrait utiliser statcomme alternative aux fichiers temporaires (comparer OSX et 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
la source
Lors de la création de fichiers temporaires, il est courant de supprimer les fichiers oubliés avec une trapcommande.
Thomas Dickey
Je suis sur MacOS 10.9.5.
Peter Grill
Merci pour la clarification. Les fichiers temporaires ne sont pas aussi élégants que certaines approches possibles reposant sur des extensions supplémentaires, mais je fournirai un court exemple de script, pour des raisons de cohérence.
Thomas Dickey
1

Une autre zshapproche:

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

Rapporterait les fichiers qui ont quelque chose qui ressemble à un horodatage dans leur nom mais qui ne correspond pas à leur dernière heure de modification.

zsha une pléthore d'opérateurs comme ça pour manipuler les globes et les variables. Il est très pratique de faire n'importe quel travail rapidement (et généralement de manière fiable), mais il est assez difficile de les comprendre tous et cela produit souvent ce que nous appelons habituellement du code en écriture seule (euphémisme pour code illisible, mais implique également que vous ne le faites pas '' t besoin de le lire pendant que vous l'écrivez pour un usage unique à l'invite de commande)

Un rapide tour d'horizon:

  • **/pattern(qualifier): glob récursif avec qualificatif glob.
  • [0-9](#c8)correspond à 8 chiffres. C'est zsh extendedglob équivalent de ksh« s {8}([0-9]).
  • D: inclure des fichiers cachés
  • e@...@: le qualificatif eval glob pour exécuter du texte afin de qualifier davantage les fichiers. Chemin d'accès au fichier transmis$REPLY
  • zstat...récupérer le mtime au format YYYYMMDD dans le $mtableau.
  • ${REPLY:t}: s'étend à la queue t (le nom de base) du fichier.
  • ${(SM)something#pattern}. Extrayez le motif de correspondance des pièces de quelque chose . Ceux S( S recherche ubstring) et M(étendre à M partie atched) sont appelés drapeaux d'extension des paramètres .
Stéphane Chazelas
la source