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.
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.
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:
-depth
de find pour activer la navigation en profondeur d'abordglobstar
du shell de bash pour activer la correspondance de modèle de fichier récursive_
: 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
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
_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
.