Erstellen Sie rekursiv Verzeichnisse für alle Buchstaben

12

Ich möchte ein Verzeichnis so anlegen, dass ich die Verzeichnisse von abis benennen muss z. In jedem dieser Verzeichnisse muss ich Unterverzeichnisse erstellen, damit sie mit usw. gekennzeichnet aasind ab.

So zum Beispiel für das Verzeichnis m, mein Unterverzeichnis als markiert werden ma, mbbis mz.

Ramesh
quelle
3
Sie brauchen nicht das erste mkdir, da -p auch die Unterverzeichnisse erstellt. Und Sie brauchen den Befehl cd nicht, wenn Sie absolute Pfade verwenden. Ansonsten ist es nett, funktioniert, Variablen deklariert usw. Die Version von Michael Homer ist kürzer und hat vielleicht eine bessere Leistung, aber für eine so einfache Aufgabe wären Ihre gut genug.
1
Früher gab es mehr termininfo-Einträge und keine bash {a..z} -Syntax, also würde ich /usr/share/terminfomit [az] auflisten und diese Ausgabe verwenden. Linux ist in dieser Hinsicht ziemlich sparsam. Früher gab es Einträge für alle Groß- und Kleinbuchstaben sowie die Ziffern.
Schemata

Antworten:

19

Versuchen:

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

Bash wird erweitert XXX{a..z}, um XXXa, XXXbund so weiter. Die innere Schleife, die Sie haben, ist nicht erforderlich.

Danach:

$ 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
quelle
7

Also, mit bashder Alphabet-Erweiterung funktioniert das:

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

Und wenn Sie das Alphabet nur einmal in der ersten Zeile eingeben, sollte das gleiche Konzept auf jede Shell übertragbar sein. Es gibt andere Möglichkeiten, um zur festgelegten Zeile zu gelangen, wenn Sie sie nicht wie folgt eingeben möchten:

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 

... funktioniert beispielsweise in einem ASCII-Gebietsschema. Sie könnten also einen set $(seq -sP32P 97 123|dc)oder einen anderen Befehl ausführen, mit dem Sie eine $IFSgetrennte Liste der von Ihnen benötigten Argumente erhalten, aber ich meine, es ist wahrscheinlich besser, das bashDing nur zu verwenden oder es einzugeben.

Jedenfalls denke ich, dass ich es so machen würde, wenn nur, weil es nur mkdirso oft wie nötig aufruft .

Und um zu demonstrieren, wie es funktioniert, hier eine kleine Debug-Ausgabe eines kleineren Sets:

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

Wie Sie sehen können, werden die forSchleifen nur einmal pro Positionsparameter-Array-Index ausgeführt, den ich hier durch einfaches Übergeben shder Parameter beim Aufruf und darüber mit festgelegt habe set ${positionals}. Aber printferhält die gleiche Anordnung in der Argumentliste für jede Iteration und wendet seine Formatstring zu jedem seiner Argumente, so dass Sie den Anschein von Rekursion ohne unnötige Rekursion erhalten.

Wenn Sie den done|commandWillen dazu hinzufügen, die gesamte forAusgabe einer Schleife auf dieselbe Weise über die Pipe zu done >filestreamen, wird alles in eine Datei gestreamt - die Ausgabedatei wird nur einmal für das gesamte for...doneKonstrukt geöffnet und geschlossen .

mikeserv
quelle
3

Von hier aus habe ich ein Skript wie dieses erstellt. Wenn ich jedoch eine elegante Lösung erhalte, akzeptiere ich sie als Antwort.

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
quelle
+1, gute Frage und bessere Antwort :)
Networker
@Networker, ich bin sicher, es gibt eine ziemlich gute Lösung als diese. Warten auf eine Expertenantwort, die den Job so ähnlich wie diese Antwort machen wird, aber viel cooler aussehen wird :)
Ramesh
Genau genommen ist es nicht erforderlich, wenn Sie wissen, wie die Variablenwerte lauten (und es handelt sich um einfache Zeichenfolgen), aber es ist eine gute Idee, sich daran zu gewöhnen, Ihre Variablen in Anführungszeichen zu setzen. Sie könnten verwenden /home/ramesh/"$x"/"$x$y", /home/ramesh/"$x/$x$y"oder "/home/ramesh/$x/$x$y"- sie sind alle gleichwertig.
Scott
1

In Perl:

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

File::Pathist Kernmodul seit Perl 5.001.

cuonglm
quelle