Créez récursivement des répertoires pour toutes les lettres

12

Je veux créer un répertoire de telle manière que je dois étiqueter les répertoires de aà z. À l'intérieur de chacun de ces répertoires, je dois créer des sous-répertoires afin qu'ils soient étiquetés comme aa, abetc.

Ainsi, par exemple, pour le répertoire m, mes sous-répertoires seront étiquetés comme ma, mbjusqu'à mz.

Ramesh
la source
3
vous n'avez pas besoin du premier mkdir car -p crée également les sous-répertoires. Et vous n'avez pas besoin de la commande cd si vous utilisez des chemins abolis. Sinon c'est sympa, ça marche, les variables sont déclarées, etc. La version de Michael Homer est plus courte et peut-être a de meilleures performances, mais pour une tâche aussi simple, la vôtre serait assez bonne.
1
À l'époque, il y avait plus d'entrées termininfo et aucune syntaxe bash {a..z}, je listais donc /usr/share/terminfoavec [az] et j'utilisais cette sortie. Linux est assez clairsemé sur ce compte, utilisé pour être des entrées pour tous les caractères majuscules et minuscules plus les chiffres.
schemathings

Réponses:

19

Essayer:

for x in {a..z} ; do mkdir -p $x/${x}{a..z} ; done

Bash étendra XXX{a..z}vers XXXa, XXXbet ainsi de suite. Vous n'avez pas besoin de la boucle intérieure que vous avez.

Après ça:

$ ls
a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z
$ ls m
ma  mc  me  mg  mi  mk  mm  mo  mq  ms  mu  mw  my
mb  md  mf  mh  mj  ml  mn  mp  mr  mt  mv  mx  mz
Michael Homer
la source
7

Donc, avec bashl'extension de l'alphabet, cela fonctionne:

set {a..z}
for a do printf "./$a/$a%s\n" "$@"
done | xargs mkdir -p

Et si vous tapez juste l'alphabet une fois dans la première ligne, le même concept devrait être portable sur n'importe quel shell. Il existe d'autres façons d'arriver à la ligne définie si vous ne voulez pas la taper comme:

seq -sP32P 97 123|dc
a b c d e f g h i j k l m n o p q r s t u v w x y z 

... par exemple, fonctionne dans un environnement local ASCII. Vous pouvez donc faire set $(seq -sP32P 97 123|dc)ou n'importe quelle autre commande qui vous obtiendrait une $IFSliste séparée des arguments dont vous avez besoin, mais, je veux dire, il vaut probablement mieux simplement utiliser la bashchose ou la taper.

Quoi qu'il en soit, je pense que c'est ainsi que je le ferais, ne serait-ce que parce qu'il n'appelle que mkdiraussi souvent que nécessaire.

Et juste pour montrer comment cela fonctionne, voici une petite sortie de débogage d'un ensemble plus petit:

sh -cx 'for n do printf "./$n/$n%s\n" "$@"; done|cat' -- arg1 arg2 arg3
+ for n in '"$@"'
+ printf './arg1/arg1%s\n' arg1 arg2 arg3
+ cat
+ for n in '"$@"'
+ printf './arg2/arg2%s\n' arg1 arg2 arg3
+ for n in '"$@"'
+ printf './arg3/arg3%s\n' arg1 arg2 arg3
./arg1/arg1arg1
./arg1/arg1arg2
./arg1/arg1arg3
./arg2/arg2arg1
./arg2/arg2arg2
./arg2/arg2arg3
./arg3/arg3arg1
./arg3/arg3arg2
./arg3/arg3arg3

Comme vous pouvez le voir, les forseules boucles une fois par index de tableau de paramètres positionnels, que j'ai défini ici en remettant simplement shles paramètres à l'invocation, et au-dessus avec set ${positionals}. Mais printfreçoit le même tableau dans sa liste d'arguments pour chaque itération et applique sa chaîne de format à chacun de ses arguments, ainsi vous obtenez l'apparence de récursivité sans aucune récursivité inutile.

Et l'ajout de done|commandva diffuser toute forla sortie d'une boucle sur le tube de la même manière done >filele diffuserait dans un fichier - n'ouvrant et fermant le fichier de sortie qu'une seule fois pour la for...doneconstruction entière .

mikeserv
la source
3

À partir de , j'ai fini par créer un script comme celui-ci. Cependant, si j'obtiens une solution élégante, je l'accepterai comme réponse.

for x in {a..z}
do
    mkdir -p /home/ramesh/$x
    cd /home/ramesh/$x
    for y in {a..z}
    do
        mkdir -p /home/ramesh/$x/$x$y
    done
done
Ramesh
la source
+1, bonne question et meilleure réponse :)
Nidal
@ Networker, je suis sûr qu'il existe une assez bonne solution que celle-ci. En attente d'une réponse d'expert qui fera le travail aussi similaire que cette réponse, mais aura l'air beaucoup plus cool :)
Ramesh
À strictement parler, ce n'est pas nécessaire lorsque vous savez quelles seront les valeurs des variables (et ce sont de simples chaînes), mais c'est une bonne idée de prendre l'habitude de citer vos variables. Vous pouvez utiliser /home/ramesh/"$x"/"$x$y", /home/ramesh/"$x/$x$y"ou "/home/ramesh/$x/$x$y"- ils sont tous équivalents.
Scott
1

Dans Perl:

perl -MFile::Path=make_path -e '
    make_path(map { $l=$_; map { "$l/$l$_" } a..z } a..z)
'

File::Pathest le module principal depuis Perl 5.001.

cuonglm
la source