Forum Programmation.shell Copier un fichier en fonction de sa date

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
-3
26
juil.
2021

Hello,

#!/bin/bash
# Copier le fichier le plus récent de la liste de fichier
# exemple
# liste : test1.txt test2.txt test3.txt
# test3.txt est le plus récent
# l'idée est : cp *.txt /folder if *.txt est le plus récent
# Quel est le moyen de réaliser se déplacement spécifique ?
# Pourquoi demander ça ? Un fichier est ajouté une fois par semaine dans le dossier, avec la date dans le nom de fichier. 
# Merci
  • # Problème d'énoncé

    Posté par  . Évalué à 3. Dernière modification le 26 juillet 2021 à 07:23.

    Il y a un problème dans l'énoncé, l'exemple n'est pas conforme à la description.

    Faut-il se baser sur le nom ou la date de création du fichier ?

    Dans le cas d'une date dans le nom du fichier, quel est son format (s'il est unique) ?

    Matricule 23415

    • [^] # Re: Problème d'énoncé

      Posté par  . Évalué à 2.

      Effectivement, cela porte à confusion. Rien à voir avec le nom du fichier, seulement sa date de création

      • [^] # Re: Problème d'énoncé

        Posté par  . Évalué à 2. Dernière modification le 26 juillet 2021 à 08:09.

        A tester/adapter alors :

        find . -type f -printf '%T@ %p\n' \
        | sort -n | tail -1 | cut -f2- -d" "

        Je suppose que si ça fait ce que ça dit, il suffit de piper ça dans un xargs cp et le tour est joué

        Matricule 23415

        • [^] # Re: Problème d'énoncé

          Posté par  (Mastodon) . Évalué à 3.

          L'intérêt de find sur ce coup c'est de faire du récursif (en plus de se faire plaisir à pondre une commande bien tordue :) ). Je ne sais pas si c'est demandé dans l'énoncé, mais il faut souligner la différence de comportement.

          En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

          • [^] # Re: Problème d'énoncé

            Posté par  . Évalué à 2.

            Tout à fait !

            On pourrait également se poser la question des environnements compatibles (de mémoire, c'était indiqué non compatible BSD sans plus de précisions). Peut-être que c'est posix, peut-être pas (je n'ai pas cherché du tout).

            Matricule 23415

        • [^] # Re: Problème d'énoncé

          Posté par  . Évalué à 2.

          à adapter, si on se base sur la date de creation, modification ou dernier acces

          il y a find . -ctime -1 ...
          pour les fichiers dont la Creation remonte à moins de 24h

          mtime pour la date de modification
          atime pour la date d'accès

  • # Suite

    Posté par  . Évalué à 1.

    Bonjour, non, rien à voir avec le nom du fichier qui contient la date. En gros, j'aimerais déplacer le fichier le plus récent dans un autre dossier

    • [^] # Re: Suite

      Posté par  (Mastodon) . Évalué à 3. Dernière modification le 26 juillet 2021 à 08:49.

      Par ordre de raisonnement :

      • ls -t *.txt trie les fichiers par ordre de date.
      • Donc ls -t *.txt | head -n 1 te donnera le fichier le plus récent.
      • cp "$(ls -t *.txt | head -n 1)" /backup copie dans /backup le fichier le plus récent.

      Tu peux utilise explainshell.com pour analyser cette ligne de commande.

      En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

      • [^] # Re: Suite

        Posté par  (site web personnel) . Évalué à 4.

        Si on veut pinailler, on notera que cette solution ne marche pas si le nom de fichier contient un retour charriot.

        (mais il faut avouer que mettre des retours charriots dans ses noms de fichiers, c'est pas très utile et ça sert surtout à casser les scripts shell pour le plaisir ;-) )

        • [^] # Re: Suite

          Posté par  (Mastodon) . Évalué à 3. Dernière modification le 26 juillet 2021 à 12:23.

          J'avoue, mettre un retour chariot dans le nom du fichier c'est assez tordu :)

          Pour y être robuste il faudrait faire quoi ? Variable intermédiaire pour le nom du fichier ?

          En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

          • [^] # Re: Suite

            Posté par  (site web personnel) . Évalué à 4.

            Pour être robuste : ne pas programmer en shell ;-). Utiliser la sortie de ls pour autre chose que l'afficher à un humain, c'est mal™.

            Dans pas mal de cas, on peut faire des trucs robustes à coup de find ... -print0, qui utilise \0 comme délimiteur (et ça, c'est effectivement interdit dans un nom de fichier), mais je ne vois pas d'équivalent de ls -t avec find, ni d'équivalent de -print0 pour ls, donc je ne vois pas de solution raisonnable en shell.

            • [^] # Re: Suite

              Posté par  (site web personnel, Mastodon) . Évalué à 1.

              Ah vous m'avez devancé… Pour répondre à la question, je verrais un truc un peu moins trivial du coup (non testé)

              find . -name '*.txt' -type f -printf "%T@ %p\0" |
               sort -n | cut -d' ' -f 2- | tail -n 1

              “It is seldom that liberty of any kind is lost all at once.” ― David Hume

              • [^] # Re: Suite

                Posté par  . Évalué à 2.

                Au copieur !

                Matricule 23415

                • [^] # Re: Suite

                  Posté par  (site web personnel, Mastodon) . Évalué à 1.

                  Sorry, je viens de voir. Mais petite différence quand même : print (toi) vs print0 (moi)

                  “It is seldom that liberty of any kind is lost all at once.” ― David Hume

              • [^] # Re: Suite

                Posté par  (site web personnel) . Évalué à 3.

                Le \0 du -printf est un début, mais il faut aussi apprendre au reste du pipe à ne découper que selon les \0 et à ignorer les \n. Pour l'instant sort -n va joyeusement trier les lignes et non les fichiers, et tail -n 1 coupera toujours la dernière ligne même si ce n'est que la moitié d'un nom de fichier.

                • [^] # Re: Suite

                  Posté par  (site web personnel, Mastodon) . Évalué à 1.

                  Ah oui, bien vu ! Correction du premier :

                  sort -zn

                  Par contre, cat/head/tail/sed et d'autres sont conçus et prévus pour traiter des lignes d'un fichier textuel au sens normal : terminés par \n Du coup, il faudrait probablement passer par AWK ou un langage de scripting…

                  # cut -d ' ' -f 2-
                  awk -F ' ' -v RS='\0' '{$1=""; print}'
                  # tail -n 1
                  awk -v RS='\0' '{newline[NR]=$0;} END{for(i=NR-1;i<=NR;i++) print newline[i]}'
                  # combine now

                  “It is seldom that liberty of any kind is lost all at once.” ― David Hume

        • [^] # Re: Suite

          Posté par  (site web personnel) . Évalué à 4.

          $ ls -t *.txt
          ls: impossible d'accéder à '*.txt': Aucun fichier ou dossier de ce type
          $ touch -- -pan.txt
          $ ls -t *.txt
          ls : option invalide -- '.'
          Saisissez « ls --help » pour plus d'informations.
          $ rm -- -pan.txt
          $ touch a.txt
          $ mkdir dir.txt
          $ ls -t ./*.txt
          ./a.txt
          
          ./dir.txt:
          

          Retour chariot, beaucoup trop de fichiers pour le '*', rendre le fichier le plus récent immutable ou même non lisible, le répertoire non modifiable, etc.

        • [^] # Re: Suite

          Posté par  (site web personnel, Mastodon) . Évalué à 1.

          Pour continuer à pinailler

          • j'ai lu qu'il voulait la date de création et non la date de dernière modification : donc -U au lieu de -t ; et on pourrait ajouter aussi -T pour harmoniser et s'éviter les dates relatives.
          • pour ne pas louper les fichiers cachés, il faudrait ajouter -A
          • outre le retour charriot, il y a aussi les caractères réservés qui pourraient semer la confusion après le globbing et l'expansion ; pour ça il faudrait terminer la liste d'option par -- puis le *.txt
          • outre les retours charriots, il peut y avoir d'autres caractères problématiques pour les commandes avec lesquelles on enchaine ; donc il faudra utiliser -b (ou en majuscule pour avoir les échappements en octal) pour éviter le traitement par défaut (qui correspond à -q interactivement et -vw en l'absence de terminal)
          • pour s'éviter des surprises avec les noms (logins et groupes) il faudrait ajouter -n (voir -og vu que cette info ne sert pas, mais faudra corriger le reste des enchaînements en conséquence)
          • comme il est intéressé par les fichiers, il peut être bien d'ajouter -p (ou -F pour aller plus loin) puis ensuite virer (par un grep -v) tout ce qui se termine par '/' ; ainsi on évite le piège du répertoire-point-t-x-t

          Tout ça pour dire que qu'il faut repasser par le man ls dans le cas présent, et éviter de l'utiliser dans les scripts si c'est possible.

          “It is seldom that liberty of any kind is lost all at once.” ― David Hume

      • [^] # Re: Suite

        Posté par  . Évalué à 2.

        Je valide ceci, pour mon cas. Merci !

      • [^] # Re: Suite

        Posté par  (site web personnel, Mastodon) . Évalué à 1.

        Me demande si on ne peut pas utiliser find au lieu de ls ?

        “It is seldom that liberty of any kind is lost all at once.” ― David Hume

  • # solutions alternatives

    Posté par  . Évalué à 4.

    S'il n'y a pas de piège dans l'énoncé, à priori tous les fichiers déjà présents on du déjà être copiés, du coup un coup de rsync fera l'affaire, car il ignorera les fichiers identiques entre le dossier source et le dossier destination.

    rsync -av /dossier/source /dossier/destination

    Ps: Toujours avec le même énoncé, et dans la même idée, tu peux créer un Makefile qui copiera tout nouveau fichier ou fichier modifié, en se basant sur les dates de modification de la source à la destination.

  • # Suite pour retour

    Posté par  . Évalué à 1.

    Ok merci, je vous fais un retour ASAP

  • # inotify

    Posté par  . Évalué à 3.

    qui va scruter le dossier, et des que le fichier sera "clos" il déclenchera la copie vers l'autre emplacement ?

    • [^] # Re: inotify

      Posté par  . Évalué à 3.

      inotify est un outil très sympa mais qui a le désagréable défaut de ne pas marcher avec les disques réseaux (par exemple).

      Et oui ! Il utilise un mécanisme de "surveillance" des événements directement dans le noyau linux. Et si le disque n'est pas local, c'est perdu.

      Bref, un bon outil, mais aux limites certaines. Attention!

  • # Commentaire supprimé

    Posté par  . Évalué à 0. Dernière modification le 31 juillet 2021 à 13:48.

    Ce commentaire a été supprimé par l’équipe de modération.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.