web-dev-qa-db-fra.com

Comment créer récursivement un répertoire dans les derniers répertoires à l'aide de la ligne de commande?

Disons que j'ai la structure de répertoires suivante dans laquelle le nom des répertoires n'a pas d'importance:

currentDir/
   Dir1
      Dir1
         Dir1 *
      Dir2 *
      Dir3 *
   Dir2
      Dir1 *
      Dir2 
         Dir1*
   Dir3*

Est-il possible de créer un répertoire nommé "Texture" uniquement dans les répertoires situés à la fin de la branche d'arbre (dans l'exemple, ils sont marqués d'un *). Je voudrais faire en sorte que seuls ces répertoires obtiennent un répertoire Texture, mais aucun autre.

Tous les répertoires peuvent ou non contenir des fichiers, mais les répertoires d'extrémité ne contiendront aucun autre répertoire.

5
kingcobra1986

Tout d'abord activer le globbing récursif

shopt -s globstar

Maintenant, nous pouvons regarder dans tous les répertoires avec **. Pour annuler la définition, vous pouvez utiliser shopt -u globstar (il est désactivé par défaut, il sera donc désactivé lorsque vous ouvrirez un nouveau shell).

Dans tout ce qui suit, supprimez echo après avoir testé la création des répertoires.

Si les répertoires de fin d’arborescence sont vides, vous pouvez tester le vide et créer le répertoire uniquement s’il est détecté ... par exemple

for d in **/; do [[ -z "$(ls -Aq "$d")" ]] && echo mkdir "$d"Texture; done

si la sortie de ls -A (hidden files except current and parent dir) -q (printing ? for non-printing characters) est vide, créez un répertoire.

Mais puisque les répertoires contiennent des fichiers, nous ferions mieux de vérifier qu'il n'y a pas de répertoires

for d in **/; do [[ -z "$(find "$d" -maxdepth 1 -mindepth 1 -type d)" ]] && echo mkdir "$d"Texture; done

mindepth -1 consiste à empêcher la recherche du répertoire en cours ... find voit les fichiers cachés, nous savons donc qu'ils sont inclus. Comme n'importe quel caractère doit réussir le test (nous voulons seulement vérifier que la sortie est vide), cela devrait être relativement sûr ...

Une manière plus concise (désolé Greg) (mais en réalité, toutes ces méthodes ont un effet similaire - nous pouvons nous permettre d'utiliser des noms de fichiers en tant que texte, car nous n'essayons pas de faire quoi que ce soit avec ces fichiers. eux-mêmes ici):

for d in **/; do (ls -Alq "$d" | grep -q '^d') || echo mkdir "$d"Textures; done

nous ajoutons ici l'indicateur -l pour les sorties longues, qui affiche chaque fichier sous la forme

drwxrwxr-x 5 zanna zanna 4096 Sep 27 22:00 Dir1

nous avons ensuite gulp canalisons ce matériel dans grep pour voir si l'une des lignes commence par d (signifiant qu'il y a un répertoire) . Nous ne voulons pas que grep imprime ce texte non fiable et dépourvu de sens. Nous vérifions donc simplement son statut de sortie avec -q pour voir s'il a trouvé quelque chose. Si ce n’est pas le cas, nous créons un répertoire (à l’aide de l’opérateur || ou, c’est-à-dire, exécutez la commande suivante si la dernière a échoué). Cela devrait fonctionner, en fait, même si vos noms de fichiers contiennent des caractères horribles tels que des nouvelles lignes, puisque ls les affiche sous la forme ? - chaque ligne devrait commence par une lettre indiquant le type de fichier, donc aucun chat ne mourra probablement.

6
Zanna

Voici un appel douloureux find -exec

Avant:

$ tree currentDir
currentDir
├── Dir1
│   ├── Dir1
│   │   └── Dir1
│   ├── Dir2
│   └── Dir3
├── Dir2
│   ├── Dir1
│   └── Dir2
│       └── Dir1
└── Dir3

Créer les répertoires de texture

$ find currentDir -depth -type d -exec bash -c 'cd "$1"; shopt -s globstar nullglob; texture=(**/Texture); [[ ${#texture[@]} -eq 0 ]] && mkdir Texture' _ '{}' \;

Cela repose sur:

  • l'option -depth de find pour activer la navigation en profondeur d'abord
  • option globstar du shell de bash pour activer la correspondance de modèle de fichier récursive
  • notez l'argument _: qui entre dans le bash var $0 afin que le chemin actuel de find puisse être bash var $1

Après

$ tree currentDir
currentDir
├── Dir1
│   ├── Dir1
│   │   └── Dir1
│   │       └── Texture
│   ├── Dir2
│   │   └── Texture
│   └── Dir3
│       └── Texture
├── Dir2
│   ├── Dir1
│   │   └── Texture
│   └── Dir2
│       └── Dir1
│           └── Texture
└── Dir3
    └── Texture
5
glenn jackman

Cela devrait fonctionner:

shopt -s globstar; for i in **/; do sub=$(find "$i" -type d | wc -l); if [[ "$sub" -eq 1 ]]; then mkdir "$i"/Texture; fi;done

Résultat:

currentDir
├── Dir1
│   ├── Dir1
│   │   └── Dir1
│   │       └── Texture
│   ├── Dir2
│   │   └── Texture
│   └── Dir3
│       └── Texture
├── Dir2
│   ├── Dir1
│   │   └── Texture
│   └── Dir2
│       └── Dir1
│           └── Texture
└── Dir3
    └── Texture
3
George Udosen

Python facilite les choses.

_python3 -c 'import os
for d in [root for root, dirs, files in os.walk(".") if not any(dirs)]:
    os.mkdir(d + "/Texture")'
_

Vous pouvez exécuter cette commande à partir de votre shell. Il passe un script de trois lignes à l'interpréteur Python , qui l'exécute. Le script crée une liste de tous les répertoires sous _._ (celui dans lequel vous vous trouvez), puis crée un sous-répertoire Texture dans chacun d'entre eux qui ne possédait pas encore de sous-répertoires.

C’est plus simple à écrire et à comprendre que la plupart des autres méthodes, car Python a une fonction os.walk qui énumère les répertoires d’une manière qui permet de voir facilement les uns ont des sous-répertoires (et plus généralement parce que Python est un langage que beaucoup d’utilisateurs trouvent propre et intuitif).

Si vous voulez simplement montrer quels nouveaux répertoires seraient créés au lieu de les créer, remplacez os.mkdir par print . Voici, si vous souhaitez copier et coller:

_python3 -c 'import os
for d in [root for root, dirs, files in os.walk(".") if not any(dirs)]:
    print(d + "/Texture")'
_

Il existe des moyens d'écrire l'une ou l'autre de ces commandes de trois lignes sur une seule ligne, mais ce n'est pas nécessaire. Vous pouvez entrer la commande que vous souhaitez utiliser dans une invite de shell interactive en la saisissant ou en la collant, ou vous pouvez l'utiliser dans un script Shell. Lorsqu'il est entré de manière interactive, votre shell imprimera _>_ (à moins que vous n'ayez défini _$PS2_ sur quelque chose de différent) au début des deuxième et troisième lignes. Ce n'est pas un problème.

Ce qui précède suppose que vous utilisez un Bourne-style Shell comme bash , dash / sh , ksh , zsh , posh , etc. ( Ceuxtroisréponses utilisez _shopt -s globstar_. Cette commande est spécifique à Bash, bien que certains autres shells ont une fonctionnalité similaire . Donc, s'ils fonctionnent pour vous, cela devrait aussi.) Si vous utilisez Ubuntu et que vous ne savez pas dans quel shell vous tapez des commandes, c'est bash . Si vous utilisez csh ou tcsh , vous devrez placer un _\_ à la fin des deux premières lignes pour éviter un _Unmatched '._ erreur, et vous verrez _?_ au lieu de _>_.

Pour tester cette méthode sur une hiérarchie de répertoires existante sans créer les répertoires, utilisez simplement la deuxième commande comme décrit ci-dessus. Mais si vous le souhaitez, vous pouvez créer une nouvelle hiérarchie de répertoires à des fins de test. _mkdir -p dir/{a/{b/c,d,e},f/{g,h/i},j}_ crée une arborescence de répertoires avec la même topologie que celle de votre exemple; _find dir -type d -exec touch {}/x \;_ le remplit avec certains fichiers afin que vous puissiez vérifier que la présence de non-répertoires n'est pas un problème; cd dir y va; vous pourrez alors tester les commandes ci-dessus, ainsi que toute autre méthode qui pourrait vous intéresser, comme celles présentées dans les autres réponses; puis lancez tree .

1
Eliah Kagan