Crea ricorsivamente directory per tutte le lettere


12

Voglio creare una directory in modo tale da dover etichettare le directory da aa z. All'interno di ciascuna di queste directory, devo creare delle sottodirectory in modo che siano etichettate come aa, abecc.

Ad esempio, per la directory m, le mie sottodirectory saranno etichettate come ma, mbfino a mz.


3
non è necessario il primo mkdir perché -p sta creando anche le sottodirectory. E non è necessario il comando cd se si usano percorsi aboluti. Altrimenti è bello, funziona, dichiarano le variabili, ecc. La versione di Michael Homer è più corta e forse ha prestazioni migliori, ma per un compito così semplice la tua sarebbe abbastanza buona.

1
In passato c'erano più voci termininfo e nessuna sintassi bash {a..z}, quindi avrei elencato /usr/share/terminfocon [az] e avrei usato quell'output . Linux è piuttosto scarso su questo punto, era usato per inserire tutti i caratteri maiuscoli e minuscoli più le cifre.
schemi del

Risposte:


19

Provare:

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

Bash si espanderà XXX{a..z}verso XXXa, XXXbe così via. Non è necessario il circuito interno che hai.

Dopo di che:

$ 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

7

Quindi, con bashl'espansione dell'alfabeto, funziona:

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

E se scrivi semplicemente l'alfabeto una volta nella prima riga, lo stesso concetto dovrebbe essere portabile su qualsiasi shell. Esistono altri modi per arrivare alla linea impostata se non si desidera digitarla come:

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 

... ad esempio funziona in una locale ASCII. Quindi potresti fare set $(seq -sP32P 97 123|dc)o qualsiasi altro comando che ti $IFSprocurerebbe un elenco separato degli argomenti di cui hai bisogno, ma, intendo, probabilmente è meglio solo usare la bashcosa o digitarla.

Ad ogni modo, penso che sia il modo in cui lo farei se non altro perché invoca solo tutte mkdirle volte che è necessario.

E solo per dimostrare come funziona, ecco un piccolo output di debug di un set più piccolo:

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

Come puoi vedere, gli forunici loop una volta per indice di array di parametri posizionali, che ho impostato semplicemente passando shi parametri su invocazione, e sopra con set ${positionals}. Ma printfriceve lo stesso array nel suo elenco di argomenti per ogni iterazione e applica la sua stringa di formato a ciascuno dei suoi argomenti, in modo da ottenere la parvenza di ricorsione senza inutili ricorsioni.

E aggiungendo lo done|commandstream tutto forl'output di un loop sulla pipe allo stesso modo done >filelo streaming tutto in un file - aprendo e chiudendo il file di output solo una volta per l'intero for...donecostrutto.


3

Da qui , ho finito per creare una sceneggiatura come questa. Tuttavia, se avrò una soluzione elegante, la accetterò come risposta.

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

+1, bella domanda e risposta migliore :)
Nidal,

@Networker, sono sicuro che ci sia una soluzione abbastanza buona di questa. In attesa di una risposta esperta che farà il lavoro in modo simile a questa risposta, ma sembrerà molto più interessante :)
Ramesh

A rigor di termini, non è necessario quando sai quali saranno i valori delle variabili (e sono stringhe semplici), ma è una buona idea prendere l'abitudine di citare le tue variabili. Puoi usare /home/ramesh/"$x"/"$x$y", /home/ramesh/"$x/$x$y"oppure "/home/ramesh/$x/$x$y"- sono tutti equivalenti.
Scott,

1

In Perl:

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

File::Pathè il modulo principale da allora Perl 5.001.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.