Por ejemplo se {a..c}{1..3}
expande a a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Si quisiera imprimir a1 b1 c1 a2 b2 c2 a3 b3 c3
, ¿hay alguna forma análoga de hacerlo? ¿Cuál es la forma más simple?
fuente
Por ejemplo se {a..c}{1..3}
expande a a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Si quisiera imprimir a1 b1 c1 a2 b2 c2 a3 b3 c3
, ¿hay alguna forma análoga de hacerlo? ¿Cuál es la forma más simple?
Podrías hacerlo:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Que luego le dice al shell que evalúe:
echo {a..c}1 {a..c}2 {a..c}3
Para este caso en particular, creo que la opción dada por Stéphane Chazelas es la mejor.
Por otro lado, cuando expande cosas más complejas, esta opción no escala bien. Entonces, puedes lograr lo mismo con esto:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
que devuelve:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Parece un poco desordenado, pero ahora, tengo un gran control en el orden, solo cambiando dos caracteres en el comando anterior; por ejemplo:
$ echo {a..b}{1..2}{a..b}{1..2}
esto se expandirá a:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Supongamos que quiero todo 1
en la segunda expansión, luego el 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
Supongamos que quiero todo a
en la tercera expansión, luego el 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
Supongamos que quiero todo 1
en la cuarta expansión, luego el 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
Supongamos que quiero todo 1a
en el medio, luego 1b
, luego 2a
, luego 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
Incluso puede, con la misma facilidad, invertir cualquier orden en las expansiones anteriores, simplemente agregando un r
comando anterior; por ejemplo, el ú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 : generalmente, si esta expansión final se va a utilizar como una lista de argumentos, el espacio final no es un problema; pero si desea deshacerse de él, puede agregarlo a cualquiera de los comandos anteriores, por ejemplo| sed 's/ $//'
; o incluso| sed 's/ $/\n/'
, cambiar ese espacio final por unnewline
Nota_2 : En los ejemplos anteriores, he usado subconjuntos de dos elementos (es decir, {a, b} y {1,2} ) solo por simplicidad en la prueba de concepto: puede usar subconjuntos de cualquier longitud finita, y comando correspondiente, sería comparable.
Una línea que funciona en (bash, ksh, zsh) (no todos los shells pueden hacer "Expansión de llaves" en orden inverso):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Una alternativa que usa eval
(que todavía es para bash, ksh, zsh y puede ser más críptico) es:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Para entender lo que sucede, reemplácelo eval
con echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
El comando ejecutado (después de la expansión eval) es en realidad echo {a..c}1 {a..c}2 {a..c}3
. Que se expande como quieras / necesites.
Hay varios proyectiles sin "expansiones de llaves", por lo que no es posible usar eso para "todos los proyectiles". Necesitamos un bucle (con un espacio en blanco al final):
$ 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
Si no debe agregar espacio final:
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
Huellas dactilares
a1 b1 c1 a2 b2 c2 a3 b3 c3
SI necesita hacer esto para muchos valores, necesitamos usar algo similar a la expansión de llaves para generar una lista de números $(seq 10)
. Y, dado que seq no puede generar una lista de letras, necesitamos convertir a ascii los números generados:
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
huellas dactilares:
a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4
yash -o braceexpand
a la lista.yash -o braceexpand -c 'echo {3..1}{c..a}'
imprime3{c..a} 2{c..a} 1{c..a}
en Linux. No es una "expansión de llaves" completa.Las expansiones de llaves
{a..c}{1..3}
se expanden de izquierda a derecha, por lo que primero obtienesa{1..3} b{1..3} c{1..3}
y luego las letras se combinan con los números ena1 a2 a3 b1 b2 b3 c1 c2 c3
. Para obtener el orden que desea, deberá usar la expresión un poco más larga de arriba.fuente
Usando un bucle:
Esto recorrerá su primera expansión y luego expandirá cada personaje con la segunda.
Si necesita la salida en una sola línea, puede eliminar
\n
:Esto no le dará una nueva línea final, pero si la pasa a un comando o variable, eso no debería ser un problema.
fuente
Esto funciona para su caso simple y se puede extender, pero rápidamente se saldría de control. Los casos más complejos para los que esto no funcionaría son fáciles de construir.
Invierta el orden de las expansiones de llaves, luego intercambie los caracteres:
fuente
Un método simple sería usar sort (el 1.2,1.2 significa que toma un personaje en la segunda posición y termina en el mismo lugar).
Si los quiere en una línea, puede usar tr así:
fuente
Hecho por el siguiente método
salida
fuente
for i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo