IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

Supprimer des fichier qui sont vieux d'une semaine


Sujet :

Shell et commandes GNU

  1. #1
    Membre habitué Avatar de islyoung2
    Homme Profil pro
    Inscrit en
    Juin 2008
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40

    Informations forums :
    Inscription : Juin 2008
    Messages : 236
    Points : 177
    Points
    177
    Par défaut Supprimer des fichier qui sont vieux d'une semaine
    Bonjours tous le monde;
    voila j'ai dans un dossier un ensemble de fichier :
    fichier_15092009.xml
    fichier_14092009.xml
    fichier_13092009.xml
    fichier_12092009.xml
    fichier_11092009.xml
    fichier_10092009.xml
    fichier_09092009.xml
    fichier_30082009.xml
    fichier_27082009.xml

    où les chiffres à la fin des nom des fichiers se sont des dates (15/09/2009 pour le 1er fichier par ex)
    je veux supprimer tous les fichiers qui sont vieux de plus d'une semaine en se basant sur les nom des fichiers, et je suis vraiment pris par le temps ce qui m'empêche de chercher une solution moi même.

    voila si quelqu'un peut m'aider à une méthode simple pour procéder je serais très reconnaissant.

  2. #2
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 552
    Points : 19 389
    Points
    19 389
    Par défaut
    quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    yAuneSemaine=$(date -d -7days +%d%m%Y)
    for file in *.xml;
     do
       Nfile=$file#*[0-9]*}
       Nfile=${Nfile%.xml}
       [[ $Nfile < $yAuneSemaine ]] && echo "rm $line"
    done
    ?
    Mais comme le souligne Jmelyn, dans le message suivant, ce code peut générer une erreur.

    Donc, je corrige :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    yAuneSemaine=$(date -u -d -7days +%s)
    for file in *.xml;
     do
       Nfile=$(date -u -d$(sed -r 's@.*_([0-9]{2})([0-9]{2})([0-9]{4})\.xml@\3\2\1@' <<<"$file") +%s)
       [[ $Nfile < $yAuneSemaine ]] && echo "rm $line"
    done
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Membre éclairé Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut
    Bonjour,

    Je ne suis pas sûr que la comparaison de dates sous la forme JJMMAAA soit sans erreur : "24 09 2009" > "01 10 2009". Or le 24 septembre survient avant le 1er octobre et devrait donc être inférieur.

    La solution est de tout passer en secondes (depuis Epoch) puis de comparer.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    oneWeekAgo=$(date -d -7days +%s)
    for file in *.xml
    do
      fileDate=$(echo $file | awk -F '[_.]' '{print mktime(substr($2, 5, 4) " " substr($2, 3, 2) " " substr($2, 1, 2) " 00 00 00")}')
      [[ $fileDate < $oneWeekAgo ]] && echo "rm $file"
    done
    Cependant le code ci-dessus est approximatif parce que $oneWeekAgo devrait être arrondi à minuit.
    Un problème bien posé est déjà résolu (H. Bergson).

  4. #4
    Membre habitué Avatar de islyoung2
    Homme Profil pro
    Inscrit en
    Juin 2008
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40

    Informations forums :
    Inscription : Juin 2008
    Messages : 236
    Points : 177
    Points
    177
    Par défaut
    Citation Envoyé par jmelyn Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    oneWeekAgo=$(date -d -7days +%s)
    for file in *.xml
    do
      fileDate=$(echo $file | awk -F '[_.]' '{print mktime(substr($2, 5, 4) " " substr($2, 3, 2) " " substr($2, 1, 2) " 00 00 00")}')
      [[ $fileDate < $oneWeekAgo ]] && echo "rm $file"
    done
    Merci beaucoup pour ta réponse, sa marche trés bien ton code, mais j'arrive pas à le comprende , si tu veux bien nous l'expliqué au cas où je voudrais modifier dans la nomination de mes fichiers ou quelque chose comme sa. merci encors

  5. #5
    Membre éclairé Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut
    À la demande générale, explications...

    J'utilise l'anglais, au travail c'est nécessaire vu la multitude de nationalités. Et les noms en anglais sont faciles à composer et très courts. Maintenant c'est une habitude.

    La variable oneWeekAgo (une semaine avant) contient la date de la semaine précédente, mais comptée en secondes depuis Epoch (standard sur les UNIX). La commande "date -d -7days +%s" donne la date (et l'heure) de maintenant moins 7 jours (-d -7days), le tout en secondes depuis Epoch (+%s). Les dates des fichiers seront comparées à cette variable: plus petit c'est trop vieux (couic), plus grand c'est bon.

    La boucle for file in *.xml; do ...; done prend chaque fichier de la forme X...X.xml du répertoire courant pour le tester et éventuellement le détruire.

    La variable fileDate (date de fichier) contient la date du fichier à tester. Pour calculer cette date, il faut l'extraire du nom: X...X_date.xml puis la transformer en secondes depuis Epoch. Pour ce faire, la commande awk est particulièrement adaptée. D'abord, il faut extraire: on remarque que la date est toujours précédée du caractère '_' et suivie du caractère '.'. Je spécifie donc ces deux caractères comme séparateurs de champs (dès que awk rencontre un de ces caractères, il sait que l'on passe au champ suivant. C'est ainsi que l'on découpe le nom du fichier en morceaux). Cela donne: awk -F '[_.]'. L'on va ainsi travailler sur le deuxième champ qui sera noté $2 dans la commande awk. Puis il faut transformer la date depuis le format JJMMAAAA en SSSS. La fonction mktime de awk (en fait GNU awk ou gawk) permet de faire ce travail. Néanmoins, le format d'entrée est: "AAAA MM JJ HH MM SS". Il est nécessaire de reformater! On mettra HH, MM et SS à zéro. La fonction substr (extraction d'une sous-chaine) va prendre AAAA (du 5e caractère, longueur de 4 caractères), puis on ajoute un espace " " puis un autre appel à substr va extraire MM (du 3e caractère, longueur de 2 caractères), puis à nouveau un espace " ". Idem pour JJ et on ajoute 00 heures 00 minutes et 00 secondes. La fonction mktime retourne la valeur en secondes de la date et print l'imprime. Tout cela part dans la variable fileDate.

    Il reste le test. C'est une sorte de if - then pour commande unique: si le résultat de [[ ... ]] est vrai, alors la commande qui suit le && sera exécutée.

    J'espère que c'est clair...
    Un problème bien posé est déjà résolu (H. Bergson).

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Points : 1 206
    Points
    1 206
    Par défaut
    Bonsoir à tous,

    Je reprends ce fil pour faire quelques remarques:

    1- Pour le posteur d'origine: ne jamais utiliser de date autrement qu'au format ISO (YYMMDD) en informatique. On voit plus haut à quelle gymnastique tout ça peut conduire.

    2- Utiliser awk pour parser une date, c'est un peu comme utiliser un canon pour tuer une mouche. Et Dieu sait si je suis un fervent utilisateur de awk! Un shell moderne dispose de substitutions de paramètres qui dispensent d'utiliser un programme extérieur et ainsi éviter de créer un sous-processus fils et les flux I/O qui en découlent.

    3- Dans une évaluation de condition [[ ... ]] , l'oprérateur < est un opérateur lexicographique, pas arithmétique. Il est plus correct d'écrire [[ cond1 -lt cond2 ]] ou bien alors utiliser la structure d'évaluation arithmétique (( cond1 < cond2 ))

    Ce qui suit devrait marcher dans Bash, Ksh et Dash (pas le produit qui lave plus blanc que blanc mais bien le shell POSIX à la mode).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    now=$(date +%s)
    for file in *.xml;do
        dte=${file##*_}; dte=${dte%.*}
        y=${dte:4}; m=${dte:2:2}; d=${dte:0:2}
        if (( $(($now-$(date -d"$y$m$d" +%s))) >= 604800 ));then
            echo $file "à effacer"
        fi
    done
    :q :q! :wq :w :w! :wq! :quit :quit! :help help helpquit quit quithelp
    :quitplease :quitnow :leave :shit ^X^C ^C ^D ^Z ^Q QUITDAMMIT
    Jabber: ripat at im.apinc.org

  7. #7
    Membre éclairé Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut
    Merci Ripat pour ces précisions. D'abord l'erreur que j'ai commise en écrivant [[ ... ]] plutôt que (( ... )). Et puis le fait d'utiliser awk juste pour reformater une date.

    Je crois que l'on peut écrire le programme comme tu l'as fait, tout en shell, ou alors n'utiliser que la commande awk comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ls -1 *.xml | awk -F '[_.]' '
    {
      fileDate=mktime(substr($2, 5, 4) " " substr($2, 3, 2) " " substr($2, 1, 2) " 00 00 00")
      if (systime() - fileDate > 604800) system("rm "$0)
    }'
    Un problème bien posé est déjà résolu (H. Bergson).

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Points : 1 206
    Points
    1 206
    Par défaut
    Ton script donne satisfaction à l'OP et c'est ce qui compte. Ici, on discute optimisation et portabilité. Juste pour se faire plaisir.

    Ce n'est pas une erreur que d'utiliser awk, c'est juste que ce n'est pas indispensable. En matière de scripts j'évite de créer des subprocess quand ce n'est pas strictement nécessaire. Surtout quand ils impliquent des I/O (pipe). L'autre désavantage que je vois, c'est l'utilisation de la fonction mktime qui est une fonction que l'on ne retrouve que dans GNUawk. Les utilisateurs de awk (original), nawk ou mawk seront coincés. Par contre le script shell que je propose est POSIX.

    Pour en revenir à ta dernière solution, tu pourrais encore l'optimiser en sortant le systime() de l'itération pour éviter qu'elle soit invoquée à chaque NR. Soit tu la sorts de awk:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #!/bin/bash
     
    ls -1 *.xml | awk -F '[_.]' -v now=$(date +%s) '
    {
      fileDate=mktime(substr($2, 5, 4) " " substr($2, 3, 2) " " substr($2, 1, 2) " 00 00 00")
      if ( now - fileDate > 604800) system("rm "$0)
     
    }'
    Soit tu mets systime() sous forme de variable dans le bloc BEGIN de awk.
    :q :q! :wq :w :w! :wq! :quit :quit! :help help helpquit quit quithelp
    :quitplease :quitnow :leave :shit ^X^C ^C ^D ^Z ^Q QUITDAMMIT
    Jabber: ripat at im.apinc.org

  9. #9
    Membre éclairé Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut
    J'aime aller plus loin que juste "ça marche". Je te suis lorsque tu évoques la non-portabilité de gawk, bien que je ne connaisse pas de distro Linux pour laquelle elle ne soit pas disponible. Et Linux est le plus répandu des Unix, non? Je te suis également pour la créations des sub-processes. Cependant, j'ai supprimé la boucle for dans laquelle se trouvait awk. Comme il n'y a qu'un seul appel à awk, j'estime que le surcoût en temps et en mémoire utilisée est faible. De plus, le code me semble assez simple, ça compte aussi. Enfin tu as encore raison pour sortir l'appel systime() qui est très lourd.
    Un problème bien posé est déjà résolu (H. Bergson).

  10. #10
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Points : 1 206
    Points
    1 206
    Par défaut
    Citation Envoyé par jmelyn Voir le message
    J'aime aller plus loin que juste "ça marche". Je te suis lorsque tu évoques la non-portabilité de gawk, bien que je ne connaisse pas de distro Linux pour laquelle elle ne soit pas disponible. Et Linux est le plus répandu des Unix, non?
    Dans le grand public oui. Pas dans le milieu professionnel ou Unix est ses enfants directs (Solaris, AIX, HP-UX) sont présent en grand nombre. Pour s'en rendre compte, il suffit de surfer sur le forum unix.com et de voir la proportion des questions d'utilisateurs Linux ou *BSD sur l'ensemble.

    Mais, ici, tu as raison on est sur un forum Linux et gawk est présent dans quasi toutes les distro. Sauf que j'aime utiliser mawk pour sa rapidité - la différence avec gawk est parfois impressionnante - et que mktime ne s'y trouve pas.

    Citation Envoyé par jmelyn Voir le message
    Je te suis également pour la créations des sub-processes. Cependant, j'ai supprimé la boucle for dans laquelle se trouvait awk. Comme il n'y a qu'un seul appel à awk, j'estime que le surcoût en temps et en mémoire utilisée est faible. De plus, le code me semble assez simple, ça compte aussi
    Exact. C'est effectivement mieux ainsi.
    :q :q! :wq :w :w! :wq! :quit :quit! :help help helpquit quit quithelp
    :quitplease :quitnow :leave :shit ^X^C ^C ^D ^Z ^Q QUITDAMMIT
    Jabber: ripat at im.apinc.org

  11. #11
    Membre éclairé Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut
    Je voudrais encore ajouter une chose afin de rendre le script plus robuste: S'il n'y a pas de fichier .xml, la commande ls renverra une erreur (cannot access *.xml: No such file or directory) qui ne doit pas être prise pour un fichier! Cela donne donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ls -1 *.xml 2> /dev/null | awk -F '[_.]' -v now=$(date +%s) '
    {
         fileDate=mktime(substr($2, 5, 4) " " substr($2, 3, 2) " " substr($2, 1, 2) " 00 00 00")
         if (now - fileDate > 604800) system("rm "$0)
    }'
    Un problème bien posé est déjà résolu (H. Bergson).

  12. #12
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Points : 1 206
    Points
    1 206
    Par défaut
    Citation Envoyé par jmelyn Voir le message
    Je voudrais encore ajouter une chose afin de rendre le script plus robuste: S'il n'y a pas de fichier .xml, la commande ls renverra une erreur (cannot access *.xml: No such file or directory) qui ne doit pas être prise pour un fichier!
    Si la commande ls sort un code > 0 elle n'ira de toute façon pas dans le pipe. Mais en redirigeant le stderr vers les oubliettes tu masques les problèmes éventuels. Je crois qu'il vaut mieux afficher l'erreur éventuelle sur la sortie standard pour informer l'utilisateur.
    :q :q! :wq :w :w! :wq! :quit :quit! :help help helpquit quit quithelp
    :quitplease :quitnow :leave :shit ^X^C ^C ^D ^Z ^Q QUITDAMMIT
    Jabber: ripat at im.apinc.org

  13. #13
    Membre éclairé Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Points : 823
    Points
    823
    Par défaut
    Tu as encore raison Ripat:
    C'est stdout de la commande qui va vers stdin de la commande suivante. Stderr va directement sur la console. Donc stdin de awk ne reçoit pas le texte de l'erreur.
    Un problème bien posé est déjà résolu (H. Bergson).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. supprimer les fichiers qui ne sont pas dans une liste
    Par jeorcal dans le forum Langage
    Réponses: 7
    Dernier message: 15/01/2011, 10h03
  2. Supprimer des fichiers depuis une liste déroulante
    Par Flo88 dans le forum VBA Access
    Réponses: 7
    Dernier message: 28/03/2008, 09h14
  3. [FTP] Supprimer des fichiers supérieurs à une date
    Par Ouark dans le forum Internet
    Réponses: 4
    Dernier message: 03/09/2007, 09h53
  4. Comment supprimer des fichiers lorsqu'on quitte une interface
    Par ZAYDOUN dans le forum Interfaces Graphiques
    Réponses: 5
    Dernier message: 23/04/2007, 23h21
  5. supprimer les fichiers qui ont des mêmes noms
    Par manaboko dans le forum Langage
    Réponses: 5
    Dernier message: 08/03/2006, 09h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo