Par exemple, se {a..c}{1..3}
développe en a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Si je voulais imprimer a1 b1 c1 a2 b2 c2 a3 b3 c3
, existe-t-il une manière analogue de le faire? Quelle est la manière la plus simple?
Par exemple, se {a..c}{1..3}
développe en a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Si je voulais imprimer a1 b1 c1 a2 b2 c2 a3 b3 c3
, existe-t-il une manière analogue de le faire? Quelle est la manière la plus simple?
Réponses:
Vous pourriez faire:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Ce qui indique ensuite au shell d'évaluer:
echo {a..c}1 {a..c}2 {a..c}3
Pour ce cas particulier, je pense que l'option donnée par Stéphane Chazelas est la meilleure.
D'un autre côté, lorsque vous développez des choses plus complexes, cette option ne s'adapte pas bien. Ainsi, vous pouvez obtenir la même chose avec ceci:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
qui renvoie:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Semble un peu désordonné, mais maintenant, j'ai un énorme contrôle dans l'ordre, juste changer deux caractères dans la commande ci-dessus; par exemple:
$ echo {a..b}{1..2}{a..b}{1..2}
cela s'étendra à:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Supposons que je veuille tout 1
dans la deuxième extension, puis 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
Supposons que je veuille tout a
dans la troisième extension, puis 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
Supposons que je veuille tout 1
dans la quatrième extension, puis 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
Supposons que je veuille tout 1a
au milieu, alors 1b
, alors 2a
, puis 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
Vous pouvez même, tout aussi facilement, inverser n'importe quel ordre dans les extensions ci-dessus, en ajoutant simplement un r
à la commande précédente; par exemple, le dernier:
$ 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
Note_1 : généralement, si cette extension finale doit être utilisée comme une liste d'arguments, l'espace de fin n'est pas un problème; mais si vous voulez vous en débarrasser, vous pouvez ajouter, par exemple, à n'importe laquelle des commandes ci-dessus| sed 's/ $//'
; ou même| sed 's/ $/\n/'
, pour changer cet espace de fuite pour unnewline
Note_2 : Dans les exemples ci-dessus, j'ai utilisé des sous-ensembles de deux éléments (c'est-à-dire: {a, b} et {1,2} ) juste pour plus de simplicité dans la preuve de concept: vous pouvez utiliser des sous-ensembles de n'importe quelle longueur finie, et le commande correspondante, serait comparable.
Un liner qui fonctionne en (bash, ksh, zsh) (tous les shells ne peuvent pas faire "l'expansion de l'accolade" dans l'ordre inverse):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Une alternative qui utilise eval
(qui est toujours pour bash, ksh, zsh et peut être plus cryptique) est:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Pour comprendre ce qui se passe, remplacez eval
par echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
La commande exécutée (après l'extension eval) l'est en fait echo {a..c}1 {a..c}2 {a..c}3
. Qui s'agrandit à votre guise / besoin.
Il y a plusieurs coquilles sans "extensions d'accolade", donc, impossible de l'utiliser pour "toutes les coquilles". Nous avons besoin d'une boucle (avec un espace blanc à la fin):
$ 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 aucun espace de fin ne doit être ajouté:
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
Impressions
a1 b1 c1 a2 b2 c2 a3 b3 c3
SI vous devez le faire pour de nombreuses valeurs, nous devons utiliser quelque chose de similaire à l'extension d'accolade pour générer une liste de nombres $(seq 10)
. Et, comme seq ne peut pas générer une liste de lettres, nous devons convertir en ascii les nombres générés:
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
impressions:
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}'
s'imprime 3{c..a} 2{c..a} 1{c..a}
sous linux. Pas une "extension complète".
{a..c}1 {a..c}2 {a..c}3
Les extensions d'accolade {a..c}{1..3}
sont étendues de gauche à droite, vous obtenez donc d'abord a{1..3} b{1..3} c{1..3}
, puis les lettres sont combinées avec les chiffres dans a1 a2 a3 b1 b2 b3 c1 c2 c3
. Pour obtenir la commande que vous souhaitez, vous devrez utiliser l'expression légèrement plus longue ci-dessus.
Utiliser une boucle:
for n in {1..3}; do printf '%s\n' {a..c}"$n"; done
Cela va parcourir votre première extension, puis étendre chaque personnage avec le second.
Si vous avez besoin de la sortie sur une seule ligne, vous pouvez supprimer \n
:
for n in {1..3}; do printf '%s ' {a..c}"$n"; done
Cela ne vous donnera pas une nouvelle ligne de fin, mais si vous la passez à une commande ou une variable qui ne devrait pas être un problème.
Cela fonctionne pour votre cas simple et peut être étendu, mais cela deviendrait rapidement incontrôlable. Les cas plus complexes pour lesquels cela ne fonctionnerait pas sont faciles à construire.
Inversez l'ordre des extensions d'accolade, puis échangez les caractères:
echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'
Une méthode simple serait d'utiliser le tri (le 1.2,1.2 signifie que vous prenez un caractère à la deuxième position et vous terminez au même endroit).
$ 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
Si vous les voulez sur une seule ligne, vous pouvez utiliser tr comme ceci:
$ 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
Fait par la méthode ci-dessous
for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"
sortie
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
à la liste.