web-dev-qa-db-fra.com

Comment obtenir récursivement tous les répertoires contenant un fichier txt avec le même nom que le répertoire contenant dans Bash?

Disons que j'ai les éléments suivants:

./
   Dir1/
      Sub1/
           Sub1.jpg
      Sub2/
           Sub2.jpg
           Sub2.png
           Sub2.txt
   Dir2/
      Sub1/
           Sub1.doc
           Sub1.txt
      Sub2/
           Sub2.jpg
           Sub2.png
           SomeTxt.txt
   Dir3/
      Dir3.txt
   Dir4/
      Sub1/
           Dir4.txt
      Some.txt

En utilisant bash (bashrc dans mon cas), comment puis-je obtenir une variable contenant tous les répertoires contenant un fichier texte (.txt) portant le même nom que le répertoire contenant? Donc, à partir de l'exemple ci-dessus, j'aimerais avoir une variable contenant ce qui suit:

./Dir1/Sub2/    
./Dir1/Sub1/
./Dir3/

Il ne devrait pas retourner ./Dir1/Sub1/ car il ne possède pas de fichier Sub1.txt.

Il ne devrait pas renvoyer ./Dir2/Sub2/ car le fichier txt qu'il contient n'est pas Sub2.txt.

Il ne devrait pas retourner ./Dir4/ ou ./Dir4/Sub1/ parce que Dir4.txt n'est pas directement dans ./Dir4/.

NOTE:

Les noms des répertoires ne doivent pas être ces noms en particulier. Ce qui est important, c'est que le nom du fichier txt corresponde au nom du répertoire contenant.

De plus, je sais que d'autres langues sont peut-être plus faciles, mais j'en ai besoin à bash.

2
kingcobra1986

Donné

$ tree somepath/
somepath/
├── Dir1
│   ├── Sub1
│   │   └── Sub1.jpg
│   └── Sub2
│       ├── Sub2.jpg
│       ├── Sub2.png
│       └── Sub2.txt
├── Dir2
│   ├── Sub1
│   │   ├── Sub1.doc
│   │   └── Sub1.txt
│   └── Sub2
│       ├── SomeTxt.txt
│       ├── Sub2.jpg
│       └── Sub2.png
├── Dir3
│   └── Dir3.txt
└── Dir4
    ├── Some.txt
    └── Sub1
        └── Dir4.txt

9 directories, 12 files

puis, avec l'option globstar du shell activée (shopt -s globstar)

for d in somepath/**/; do
    d="${d%/}"
    [[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"
done
somepath/Dir1/Sub2
somepath/Dir2/Sub1
somepath/Dir3

Si vous souhaitez stocker les résultats dans un tableau pour un traitement ultérieur, vous pouvez le faire en utilisant le mapfile intégré au shell (ou son synonyme readarray), par exemple.

mapfile -t TXT_DIRS < <(
  for d in somepath/**/; do
    d="${d%/}"
    [[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"
  done
)

REMARQUE: , il serait préférable de mettre la liste en terminaison nulle en utilisant l'une des méthodes décrites dans . bash: utilisation procédurale de find dans select dans les espaces libres

Vous pouvez ensuite parcourir le tableau comme si

for d in "${TXT_DIRS[@]}"; do
    echo "$d"
done
somepath/Dir1/Sub2
somepath/Dir2/Sub1
somepath/Dir3

Alternativement, vous pouvez éviter de stocker les résultats et simplement traiter chaque répertoire au fur et à mesure que vous le trouvez, c'est-à-dire.

for d in somepath/**/; do 
    d="${d%/}"
    [[ -f "${d}/${d##*/}.txt" ]] && echo "Doing something with $d"
done
Doing something with somepath/Dir1/Sub2
Doing something with somepath/Dir2/Sub1
Doing something with somepath/Dir3
3
steeldriver

C'est pratiquement la même chose que la réponse de steeldriver, mais elle passe en boucle sur chaque fichier txt au lieu de chaque répertoire. J'espère que c'est aussi plus facile à comprendre.

Comme vous avez mentionné dans un commentaire que vous n’avez pas réellement besoin d’un tableau, j’ai omis cette étape.

shopt -s globstar
for f in ./**/*.txt; do
    d="$(dirname "$f")"
    if [[ $(basename "$f") == $(basename "$d").txt ]]; then
        printf '%s\n' "$d"
    fi
done

Sortie:

./Dir1/Sub2
./Dir2/Sub1
./Dir3
0
wjandrea