Rekurencyjnie twórz katalogi dla wszystkich liter

12

Chcę utworzyć katalog w taki sposób, że muszę oznaczyć katalogi od ado z. Wewnątrz każdego z tych katalogów, muszę utworzyć podkatalogi tak, że są one oznaczone jako aa, abetc.

Tak więc, na przykład, do katalogu m, moi podkatalogi będą oznaczone jako ma, mbdo września mz.

Ramesh
źródło
3
nie potrzebujesz pierwszego mkdir, ponieważ -p tworzy również podkatalogi. I nie potrzebujesz komendy cd, jeśli używasz abolutnych ścieżek. W przeciwnym razie jest to fajne, działające, zadeklarowane zmienne itp. Wersja Michaela Homera jest krótsza i może ma lepszą wydajność, ale przy tak prostym zadaniu twoje byłoby wystarczająco dobre.
1
W tamtych czasach było więcej wpisów termininfo i brak składni bash {a..z}, więc wyliczyłem /usr/share/terminfo[az] i użyłem tego wyjścia. Linux jest dość rzadki pod tym względem, kiedyś były to wpisy dla wszystkich wielkich i małych znaków plus cyfr.
schematy

Odpowiedzi:

19

Próbować:

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

Bash rozwinie XXX{a..z}się XXXa, XXXbi tak dalej. Nie ma potrzeby korzystania z wewnętrznej pętli.

Po tym:

$ 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
źródło
7

Tak więc w przypadku bashrozszerzenia alfabetu działa to:

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

A jeśli po prostu wpiszesz alfabet raz w pierwszym wierszu, ta sama koncepcja powinna być przenośna dla dowolnej powłoki. Istnieją inne sposoby dotarcia do ustawionej linii, jeśli nie chcesz jej wpisywać:

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 

... na przykład działa w ustawieniach ASCII. Możesz więc wykonać set $(seq -sP32P 97 123|dc)dowolną inną komendę, która da ci $IFSoddzielną listę argumentów, których potrzebujesz, ale oznacza to, że prawdopodobnie lepiej po prostu użyć tej bashrzeczy lub ją wpisać.

W każdym razie myślę, że tak właśnie bym to zrobił, choćby dlatego, że wywołuje się mkdirtak często, jak to konieczne.

Aby pokazać, jak to działa, oto mały wynik debugowania mniejszego zestawu:

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

Jak widać, forjedyne pętle raz na indeks tablicy parametrów pozycyjnych, które tutaj ustawiłem, po prostu przekazując shparametry przy wywołaniu, i powyżej za pomocą set ${positionals}. Ale printfotrzymuje tę samą tablicę z listy argumentów dla każdej iteracji i stosuje ciąg formatu do każdego z argumentów, dzięki czemu uzyskuje się pozór rekurencji bez zbędnej rekurencji.

A dodanie done|commandstrumienia przesyła strumieniowo wszystkie dane forwyjściowe pętli przez potok w ten sam sposób done >file, przesyła je strumieniowo do pliku - otwierając i zamykając plik wyjściowy tylko raz dla całej for...donekonstrukcji.

mikeserv
źródło
3

Od tutaj , skończyło się na tworzeniu skryptu takiego. Jeśli jednak dostanę eleganckie rozwiązanie, zaakceptuję je jako odpowiedź.

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
źródło
+1, dobre pytanie i lepsza odpowiedź :)
Nidal
@Networker, jestem pewien, że istnieje całkiem dobre rozwiązanie niż to. Oczekiwanie na odpowiedź eksperta, która wykona zadanie tak samo jak ta odpowiedź, ale będzie wyglądać znacznie fajniej :)
Ramesh
Ściśle mówiąc, nie jest konieczne, gdy wiesz, jakie będą wartości zmiennych (i są to proste łańcuchy), ale dobrym pomysłem jest przyzwyczajenie się do cytowania zmiennych. Możesz użyć /home/ramesh/"$x"/"$x$y", /home/ramesh/"$x/$x$y"lub "/home/ramesh/$x/$x$y"- wszystkie są równoważne.
Scott
1

W Perl:

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

File::Pathod tego czasu jest modułem podstawowym Perl 5.001.

Cuonglm
źródło