Crie recursivamente diretórios para todas as letras

12

Quero criar um diretório de forma que precise rotular os diretórios de apara z. Dentro de cada um desses diretórios, eu preciso criar sub-diretórios para que eles sejam rotulados como aa, abetc.

Então, por exemplo, para o diretório m , os meus sub-diretórios serão marcados como ma, mbaté mz.

Ramesh
fonte
3
você não precisa do primeiro mkdir porque -p também está criando os subdiretórios. E você não precisa do comando cd se usar caminhos abolutos. Caso contrário, é agradável, funcional, variáveis ​​declaradas etc. A versão de Michael Homer é mais curta e talvez tenha melhor desempenho, mas para uma tarefa tão simples a sua seria boa o suficiente.
1
No dia anterior, havia mais entradas termininfo e nenhuma sintaxe bash {a..z}, então eu listaria /usr/share/terminfocom [az] e usaria essa saída. O Linux é bastante escasso nessa contagem, costumava ser entradas para todos os caracteres maiúsculos e minúsculos, além dos dígitos.
schemathings

Respostas:

19

Experimentar:

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

O Bash se expandirá XXX{a..z}paraXXXa , XXXbe assim por diante. Não há necessidade do loop interno que você possui.

Depois disso:

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

Então, com basha expansão do alfabeto, isso funciona:

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

E se você digitar o alfabeto uma vez na primeira linha, o mesmo conceito deve ser portátil para qualquer shell. Existem outras maneiras de chegar à linha definida, se você não quiser digitá-la como:

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 

... por exemplo, trabalha em um código de idioma ASCII. Então você pode fazer set $(seq -sP32P 97 123|dc)ou qualquer outro comando que lhe forneça uma $IFSlista separada dos argumentos de que você precisa, mas, quero dizer, provavelmente é melhor apenas usar a bashcoisa ou digitá-la.

Enfim, acho que é assim que eu faria, apenas porque invoca mkdirquantas vezes for necessário.

E apenas para demonstrar como funciona, aqui está uma pequena saída de depuração de um conjunto menor:

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

Como você pode ver, os forúnicos loops uma vez por índice de matriz de parâmetros posicionais, que eu defini aqui simplesmente entregando shos parâmetros na invocação e acima com set ${positionals}. Mas printfrecebe a mesma matriz em sua lista de argumentos para cada iteração e aplica sua cadeia de formatação a cada um de seus argumentos, para obter a aparência de recursão sem nenhuma recursão desnecessária.

E adicionar o done|commandfluxo de toda fora saída de um loop sobre o canal da mesma maneira done >filetransmitiria tudo em um arquivo - apenas abrindo e fechando o arquivo de saída uma vez para toda a for...doneconstrução.

mikeserv
fonte
3

A partir daqui , acabei criando um script como este. No entanto, se eu conseguir uma solução elegante, aceitarei como resposta.

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
fonte
+1, boa pergunta e melhor resposta :)
Nidal
@ Networker, tenho certeza de que existe uma solução muito boa do que esta. À espera de alguma resposta de peritos que irá fazer o trabalho tão semelhantes quanto esta resposta, mas vai olhar muito mais frio :)
Ramesh
Estritamente falando, não é necessário quando você sabe quais serão os valores das variáveis ​​(e são simples), mas é uma boa idéia adquirir o hábito de citar suas variáveis. Você pode usar /home/ramesh/"$x"/"$x$y", /home/ramesh/"$x/$x$y"ou "/home/ramesh/$x/$x$y"- todos são equivalentes.
22414 Scott
1

Em Perl:

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

File::Pathé o módulo principal desde então Perl 5.001.

cuonglm
fonte