Por exemplo, {a..c}{1..3}
expande para a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Se eu quisesse imprimir a1 b1 c1 a2 b2 c2 a3 b3 c3
, existe uma maneira análoga de fazer isso? Qual é a maneira mais simples?
fonte
Por exemplo, {a..c}{1..3}
expande para a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Se eu quisesse imprimir a1 b1 c1 a2 b2 c2 a3 b3 c3
, existe uma maneira análoga de fazer isso? Qual é a maneira mais simples?
Você poderia fazer:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
O que então diz ao shell para avaliar:
echo {a..c}1 {a..c}2 {a..c}3
Para este caso em particular, acho que a opção dada por Stéphane Chazelas é a melhor.
Por outro lado, quando você expande coisas mais complexas, essa opção não é bem dimensionada. Então, você pode conseguir o mesmo com isso:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
que retorna:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Parece um pouco confuso, mas agora, eu tenho um controle enorme na ordem, apenas alterando dois caracteres no comando acima; por exemplo:
$ echo {a..b}{1..2}{a..b}{1..2}
isso será expandido para:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Suponha que eu queira tudo 1
na segunda expansão e, em seguida, o 2
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.2 | tr '\0' ' '
a1a1 a1a2 a1b1 a1b2 b1a1 b1a2 b1b1 b1b2 a2a1 a2a2 a2b1 a2b2 b2a1 b2a2 b2b1 b2b2
Suponha que eu queira tudo a
na terceira expansão e, em seguida, o b
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.3,1.3 | tr '\0' ' '
a1a1 a1a2 a2a1 a2a2 b1a1 b1a2 b2a1 b2a2 a1b1 a1b2 a2b1 a2b2 b1b1 b1b2 b2b1 b2b2
Suponha que eu queira tudo 1
na quarta expansão, depois o 2
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.4,1.4 | tr '\0' ' '
a1a1 a1b1 a2a1 a2b1 b1a1 b1b1 b2a1 b2b1 a1a2 a1b2 a2a2 a2b2 b1a2 b1b2 b2a2 b2b2
Suponha que eu queira tudo 1a
no meio, então 1b
, então 2a
, então 2b
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.3 | tr '\0' ' '
a1a1 a1a2 b1a1 b1a2 a1b1 a1b2 b1b1 b1b2 a2a1 a2a2 b2a1 b2a2 a2b1 a2b2 b2b1 b2b2
Você pode, com a mesma facilidade, reverter qualquer ordem nas expansões acima, apenas adicionando um r
ao comando anterior; por exemplo, o último:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -rzk 1.2,1.3 | tr '\0' ' '
b2b2 b2b1 a2b2 a2b1 b2a2 b2a1 a2a2 a2a1 b1b2 b1b1 a1b2 a1b1 b1a2 b1a1 a1a2 a1a1
Nota_1 : geralmente, se essa expansão final for usada como uma lista de argumentos, o espaço à direita não será um problema; mas se você quiser se livrar dele, pode adicionar a qualquer um dos comandos acima, por exemplo| sed 's/ $//'
; ou até mesmo| sed 's/ $/\n/'
, para alterar esse espaço à direitanewline
Nota_2 : Nos exemplos acima, usei subconjuntos de dois elementos (por exemplo: {a, b} e {1,2} ) apenas para simplificar a prova de conceito: você pode usar subconjuntos de qualquer comprimento finito e o comando correspondente, seria comparável.
Um liner único que funciona em (bash, ksh, zsh) (nem todos os shells podem fazer "Brace expansion" na ordem inversa):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Uma alternativa usada eval
(que ainda é para bash, ksh, zsh e pode ser mais enigmática) é:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Para entender o que acontece, substitua eval
por echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
O comando executado (após a expansão de avaliação) é realmente echo {a..c}1 {a..c}2 {a..c}3
. O que se expande conforme você deseja / precisa.
Existem vários shells sem "expansões de chaves", portanto, não é possível usá-los para "todos os shells". Precisamos de um loop (com um espaço em branco à direita):
$ for i in 1 2 3; do for j in a b c; do printf "%s%s " "$j" "$i"; done; done; echo
a1 b1 c1 a2 b2 c2 a3 b3 c3
Se você não deve adicionar espaço à direita:
s=""
for i in 1 2 3; do
for j in a b c; do
printf "%s%s%s" "$s" "$j" "$i"
s=" "
done
done
echo
Impressões
a1 b1 c1 a2 b2 c2 a3 b3 c3
Se você precisar fazer isso para muitos valores, precisamos usar algo semelhante à expansão de chaves para gerar uma lista de números $(seq 10)
. E, como o seq não pode gerar uma lista de letras, precisamos converter para ascii os números gerados:
s=""
for i in $(seq 4); do
for j in $(seq 5); do
printf "%s\\$(printf %03o $((96+j)))%s" "$s" "$i"
s=" "
done
done
echo
impressões:
a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4
yash -o braceexpand
à lista.yash -o braceexpand -c 'echo {3..1}{c..a}'
imprime3{c..a} 2{c..a} 1{c..a}
no linux. Não é uma "expansão de chave" completa.As expansões de chaves
{a..c}{1..3}
são expandidas da esquerda para a direita, para que você obtenha primeiroa{1..3} b{1..3} c{1..3}
e, em seguida, as letras sejam combinadas com os números ema1 a2 a3 b1 b2 b3 c1 c2 c3
. Para obter o pedido desejado, você terá que usar a expressão um pouco mais longa acima.fonte
Usando um loop:
Isso percorrerá sua primeira expansão e depois expandirá cada caractere com a segunda.
Se você precisar da saída toda em uma linha, poderá remover o
\n
:Isso não fornecerá uma nova linha à direita, mas se você a estiver passando para um comando ou variável que não deve ser um problema.
fonte
Isso funciona para o seu caso simples e pode ser estendido, mas rapidamente sairia do controle. Casos mais complexos para os quais isso não funcionaria são fáceis de construir.
Inverta a ordem das expansões de chaves e troque os caracteres:
fonte
Um método simples seria usar a classificação (o 1.2,1.2 significa que você pega um caractere na segunda posição e termina no mesmo lugar).
Se você os quiser em uma linha, use tr da seguinte maneira:
fonte
Feito pelo método abaixo
saída
fonte
for i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo