Ad esempio si {a..c}{1..3}
espande a a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Se volessi stampare a1 b1 c1 a2 b2 c2 a3 b3 c3
, c'è un modo analogo per farlo? Qual è il modo più semplice?
Ad esempio si {a..c}{1..3}
espande a a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Se volessi stampare a1 b1 c1 a2 b2 c2 a3 b3 c3
, c'è un modo analogo per farlo? Qual è il modo più semplice?
Risposte:
Potresti fare:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Che poi dice alla shell di valutare:
echo {a..c}1 {a..c}2 {a..c}3
Per questo caso particolare, penso che l'opzione data da Stéphane Chazelas sia la migliore.
D'altra parte, quando espandi cose più complesse, questa opzione non si adatta bene. Quindi, puoi ottenere lo stesso con questo:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
che ritorna:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Sembra un po 'disordinato, ma ora ho un enorme controllo nell'ordine, cambiando solo due caratteri nel comando sopra; per esempio:
$ echo {a..b}{1..2}{a..b}{1..2}
questo si espanderà a:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Supponiamo che io voglia tutto 1
nella seconda espansione, quindi 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
Supponiamo che io voglia tutto a
nella terza espansione, quindi il 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
Supponiamo che io voglia tutto 1
nella quarta espansione, quindi il 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
Supponiamo che io voglia tutto 1a
nel mezzo, quindi 1b
, quindi 2a
, quindi 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
Puoi anche, altrettanto facilmente, invertire qualsiasi ordine nelle espansioni sopra, semplicemente aggiungendo un r
al comando precedente; ad esempio l'ultimo:
$ 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 : di solito, se questa espansione finale verrà utilizzata come un elenco di argomenti, lo spazio finale non è un problema; ma se vuoi sbarazzartene, puoi aggiungere, ad esempio, uno dei comandi sopra| sed 's/ $//'
; o anche| sed 's/ $/\n/'
, per cambiare quello spazio finale per anewline
Note_2 : Negli esempi precedenti, ho usato sottoinsiemi di due elementi (ad esempio: {a, b} e {1,2} ) solo per semplicità nella dimostrazione del concetto: è possibile utilizzare sottoinsiemi di qualsiasi lunghezza finita, e il comando corrispondente, sarebbe comparabile.
Un solo liner che funziona in (bash, ksh, zsh) (non tutte le shell possono fare "espansione del controvento" in ordine inverso):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Un'alternativa che usa eval
(che è ancora per bash, ksh, zsh e può essere più criptica) è:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Per capire cosa succede, sostituiscilo eval
con echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
Il comando eseguito (dopo l'espansione eval) è in realtà echo {a..c}1 {a..c}2 {a..c}3
. Che si espande come vuoi / hai bisogno.
Esistono diverse shell senza "espansioni di controventi", quindi non è possibile utilizzarle per "tutte le shell". Abbiamo bisogno di un ciclo (con uno spazio bianco finale):
$ 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 non è necessario aggiungere spazio finale:
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
stampe
a1 b1 c1 a2 b2 c2 a3 b3 c3
Se è necessario eseguire questa operazione per molti valori, è necessario utilizzare qualcosa di simile all'espansione del controvento per generare un elenco di numeri $(seq 10)
. E, poiché seq non può generare un elenco di lettere, dobbiamo convertire in ascii i numeri generati:
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
stampe:
a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4
yash -o braceexpand -c 'echo {3..1}{c..a}'
stampa 3{c..a} 2{c..a} 1{c..a}
in linux. Non è una "espansione di rinforzo" completa.
{a..c}1 {a..c}2 {a..c}3
Le espansioni di parentesi graffe {a..c}{1..3}
vengono espanse da sinistra a destra, quindi prima ottieni a{1..3} b{1..3} c{1..3}
e poi le lettere vengono combinate con i numeri in a1 a2 a3 b1 b2 b3 c1 c2 c3
. Per ottenere l'ordine desiderato, dovrai usare l'espressione leggermente più lunga sopra.
Utilizzando un loop:
for n in {1..3}; do printf '%s\n' {a..c}"$n"; done
Questo passerà attraverso la tua prima espansione e quindi espanderà ogni personaggio con la seconda.
Se hai bisogno dell'output tutto su una riga puoi rimuovere \n
:
for n in {1..3}; do printf '%s ' {a..c}"$n"; done
Questo non ti darà una nuova riga finale, ma se lo stai passando a un comando o una variabile non dovrebbe essere un problema.
Questo funziona per il tuo caso semplice e può essere esteso, ma sfuggirebbe rapidamente alla mano. I casi più complessi per i quali questo non funzionerebbe sono facili da costruire.
Invertire l'ordine delle espansioni del controvento, quindi scambiare i caratteri:
echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'
Un metodo semplice sarebbe usare l'ordinamento (1.2.1.2 significa che prendi un carattere nella seconda posizione e finisci nello stesso posto).
$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2
a1
b1
c1
a2
b2
c2
a3
b3
c3
Se li vuoi in una riga, puoi usare tr in questo modo:
$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2|tr '\n' ' '
a1 b1 c1 a2 b2 c2 a3 b3 c3
Fatto con il metodo seguente
for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"
produzione
a1 b1 c1 a2 b2 c2 a3 b3 c3 a4 b4 c4 a5 b5 c5 a6 b6 c6 a7 b7 c7 a8 b8 c8 a9 b9 c9 a10 b10 c10
for i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo
yash -o braceexpand
all'elenco.