Forum Programmation.shell Suppression d'un fichier raw si et seulement si le fichier jpg de même préfixe existe

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
1
18
fév.
2021

Bonjour,

J'aimerais supprimer les fichiers <nom>.dng d'un répertoire donné, si et seulement si <nom>.jpg existe, quel que soit <nom>.

Idéalement j'aimerais pouvoir lancer la commande récursivement sur une arborescence.

Merci d'avance de votre aide (non, ce n'est pas un devoir scolaire, j'ai largement dépassé l'âge ;-).

  • # À décomposer

    Posté par  (site Web personnel) . Évalué à 2.

    Je verrai trois étapes différentes, la première consiste à rechercher récursivement tous les fichiers raw qui se trouvent dans le répertoire :

    find . -name '*.raw' -print

    La seconde, consiste à remplacer le print qui affiche actuellement le fichier trouvé, et en mettant la place le fichier que l'on cherche :

    echo 'fichier.raw' | sed -e 's/raw/jpg/'

    il ne reste plus qu'à assembler les deux ensemble

    find . -name '*.raw' -exec echo {} \; | sed -e 's/raw/jpg/'

    Après il ne reste plus qu'a supprimer les éléments de la liste… que je mettrai dans une boucle (mais il y a peut être plus performant ?)

    • [^] # Re: À décomposer

      Posté par  . Évalué à 2.

      Merci d'avoir pris la peine de répondre.

      J'ai essayé ton script sur cet exemple :

      a.jpg a.raw b.jpg b.raw c.raw

      j'obtiens cette liste de fichiers à supprimer :

      ./a.jpg
      ./b.jpg
      ./c.jpg

      alors que dans cet exemple, il ne faut supprimer que a.raw et b.raw (mais pas c.raw car il n'existe pas de c/jpg).

      J'ai raté quelque chose ?

      • [^] # Re: À décomposer

        Posté par  (site Web personnel) . Évalué à 2.

        Ah j'ai inversé, j'ai cru que tu voulais supprimer les jpeg dont tu possédais les fichiers raw :) (ce qui correspondrait à ma manière de gérer mes fichiers)

        Il suffit d'inverser dans la commandes pour avoir le bon comportement !

  • # bashisme

    Posté par  . Évalué à 2. Dernière modification le 18/02/21 à 17:33.

    #!/bin/bash
    
    #liste les fichiers DNF
    MALISTE=$(find . -type f -iname '*.dng')
    
    for FICHIER in ${MALISTE[@]}
    do
      # test si le fichier (dans dng, mais avec jpg) existe
      if [ -e ${FICHIER%.dng}.jpg ]
      then
        rm -v ${FICHIER}
      else
        echo "pas de fichier jpg pour ${FICHIER}"
      fi
    done

    version pas testée, juste un brouillon

    à faire tourner dans un dossier de test dans un premier temps

    • [^] # Re: bashisme

      Posté par  . Évalué à 2.

      (J'ai ajouté un " manquant dans la ligne echo "pas de fichier jpg pour ${FICHIER})

      Ça me dit :

      pas de fichier jpg pour ./a.raw
      pas de fichier jpg pour ./b.raw
      pas de fichier jpg pour ./c.raw

      ce qui n'est vrai que pour c.raw.

    • [^] # Re: bashisme

      Posté par  . Évalué à 2. Dernière modification le 18/02/21 à 15:50.

      Attention aux noms de fichiers qui pourraient contenir un caractère espace ou autre piège de ce genre
      => entourer les noms de variable par des guillemets


      Il manque un caractère . dans : ${FICHIER%dng}.jpg
      => à remplacer par "${FICHIER%.dng}.jpg"

    • [^] # Re: bashisme

      Posté par  . Évalué à 1.

      MALISTE=$(find . -type f -iname '*.dng')

      L'option iname ajoutera les fichiers dont le nom d'extension est DNG
      ce qui n'est pas demandé.

      Créé de cette façon,
      la variable MALISTE ne sera pas un tableau mais une chaîne de caractère.

  • # avec le shell bash

    Posté par  . Évalué à 2.

    Bonjour

    tblDng=( /chemin/nomRepertoire/*.dng )
    for f in "${tblDng[@]}"; do test -f "${f%.*}.jpg" && rm "$f"; done
    • [^] # Re: avec le shell bash

      Posté par  . Évalué à 2. Dernière modification le 18/02/21 à 15:51.

      Ça marche, merci !

      Merci également aux autres pour leurs variantes.

    • [^] # Re: avec le shell bash

      Posté par  . Évalué à 2.

      Il y a un moyen de rendre ça récursif ?

      Les photos en question sont classées dans une arborescence de type année/mois, ce qui représente au moins 60 répertoires. J'aimerais donc pouvoir lancer le script à la racine des répertoires d'années. D'un autre coté, j'imagine qu'on ne peut pas charger la barque de tblDng avec des milliers de noms de fichiers ?

      • [^] # Re: avec le shell bash

        Posté par  . Évalué à 1. Dernière modification le 18/02/21 à 16:20.

        Ligne de commande à lancer depuis
        la racine de l'arborescence à traiter :

        find . -type f -name '*.dng' -exec bash -c 'f="$0";test -f "${f%.*}.jpg" && rm "$f"' {} \;
        • [^] # Re: avec le shell bash

          Posté par  . Évalué à 3.

          Merci !

          • [^] # Re: avec le shell bash

            Posté par  . Évalué à 2. Dernière modification le 18/02/21 à 16:52.

            Salut,

            avec des milliers de noms de fichiers

            T'inquiète pas pour ça. Si tu fais de la conversion d'image, tu pourrais en avoir des millions de noms de fichiers que ça ne poserait pas de problème non plus ;)

            Matricule 23415

            • [^] # Re: avec le shell bash

              Posté par  . Évalué à 2.

              je crois qu'il y a quand meme une limite au nombre d'argument d'une commande ;)

              • [^] # Re: avec le shell bash

                Posté par  . Évalué à 2. Dernière modification le 18/02/21 à 18:07.

                Salut,

                Oui, probablement (j'en sais rien en fait).

                Je pensais juste au stockage en mémoire d'un tableau de chaînes versus des images à traiter (une à une) ;)

                Mais je crois que tu avais déjà compris… :)

                Matricule 23415

              • [^] # Re: avec le shell bash

                Posté par  . Évalué à 1.

                xargs --show-limits

      • [^] # Re: avec le shell bash

        Posté par  . Évalué à 3.

        En activant l'option globstar (shopt -s globstar), l'expression **/*.raw prendra tous les fichiers raw à n'importe quelle profondeur de l'arborescence, et contrairement aux bidouillages avec find ça fonctionnera aussi si les noms contiennent des caractères spéciaux.

  • # Pour ajouter un grain de shell dash (sh)

    Posté par  . Évalué à 2.

    Ligne de commande pour le shell sh (<=> sur debian : /usr/bin/dash)
    à lancer depuis la racine du système de fichiers à traiter :

    find . -type f -name '*.dng' -execdir sh -c 'f="$0";test -f "${f%.*}.jpg" && rm "$f"' {} \;
  • # C'est drole ça ...

    Posté par  . Évalué à 1. Dernière modification le 19/02/21 à 11:12.

    Bon j'ai lu trop vite ton message … pardon pour la pollution

    eric.linuxfr@sud-ouest.org

  • # Python

    Posté par  (site Web personnel) . Évalué à 2.

    Si les basheries sont trop cryptiques, python c'est bien aussi :

    import sys
    from pathlib import Path
    
    root_dir = Path(sys.argv[1])
    
    for raw_file in root_dir.rglob('*.dng'):
        if raw_file.with_suffix('.jpg').exists():
            raw_file.unlink()

    Matthieu Gautier|irc:starmad

Suivre le flux des commentaires

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