Zum Beispiel {a..c}{1..3}
erweitert um a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Wenn ich drucken wollte a1 b1 c1 a2 b2 c2 a3 b3 c3
, gibt es eine analoge Möglichkeit, dies zu tun? Was ist der einfachste Weg?
Zum Beispiel {a..c}{1..3}
erweitert um a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Wenn ich drucken wollte a1 b1 c1 a2 b2 c2 a3 b3 c3
, gibt es eine analoge Möglichkeit, dies zu tun? Was ist der einfachste Weg?
Antworten:
Du könntest es tun:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Was dann der Shell sagt, dass sie auswerten soll:
echo {a..c}1 {a..c}2 {a..c}3
Für diesen speziellen Fall denke ich, dass die Option von Stéphane Chazelas gegeben für die beste.
Wenn Sie dagegen komplexere Dinge erweitern, lässt sich diese Option nicht gut skalieren. So können Sie dasselbe erreichen:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
was zurückgibt:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Scheint ein wenig chaotisch zu sein, aber jetzt habe ich eine große Kontrolle in der Reihenfolge und ändere nur zwei Zeichen im obigen Befehl. beispielsweise:
$ echo {a..b}{1..2}{a..b}{1..2}
dies wird sich ausdehnen auf:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Angenommen, ich möchte alle 1
in der zweiten Erweiterung, dann die 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
Angenommen, ich möchte alle a
in der dritten Erweiterung, dann die 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
Angenommen, ich möchte alle 1
in der vierten Erweiterung, dann die 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
Angenommen, ich möchte alles 1a
in der Mitte haben, dann 1b
, dann 2a
, dann 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
Genauso einfach können Sie die Reihenfolge in den obigen Erweiterungen umkehren, indem Sie r
dem vorherigen Befehl einfach ein hinzufügen . Zum Beispiel die letzte:
$ 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
Anmerkung_1 : Wenn diese letzte Erweiterung als Liste von Argumenten verwendet wird, ist das nachfolgende Leerzeichen normalerweise kein Problem. aber wenn Sie es loswerden möchten, können Sie zum Beispiel einen der obigen Befehle hinzufügen| sed 's/ $//'
; oder sogar| sed 's/ $/\n/'
, um diesen abschließenden Raum für a zu ändernnewline
Anmerkung_2 : In den obigen Beispielen habe ichzur Vereinfachung des Proof of ConceptTeilmengen von zwei Elementen (dh {a, b} und {1,2} ) verwendet: Sie können Teilmengen beliebiger endlicher Länge verwenden entsprechender Befehl, wäre vergleichbar.
Ein Einzeiler, der in (bash, ksh, zsh) funktioniert (nicht alle Shells können die "Klammererweiterung" in umgekehrter Reihenfolge ausführen):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Eine Alternative, die verwendet wird eval
(die immer noch für bash, ksh, zsh und möglicherweise kryptischer ist), ist:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Um zu verstehen, was passiert, ersetzen Sie eval
durch echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
Der ausgeführte Befehl (nach eval expansion) ist tatsächlich echo {a..c}1 {a..c}2 {a..c}3
. Welches erweitert, wie Sie wollen / brauchen.
Es gibt mehrere Shells ohne "Klammererweiterungen", daher ist es nicht möglich, diese für "alle Shells" zu verwenden. Wir brauchen eine Schleife (mit einem nachgestellten Leerzeichen):
$ 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
Wenn Sie keinen abschließenden Speicherplatz hinzufügen müssen:
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
Druckt
a1 b1 c1 a2 b2 c2 a3 b3 c3
WENN Sie dies für viele Werte tun müssen, müssen Sie etwas Ähnliches wie die geschweifte Klammer verwenden, um eine Liste von Zahlen zu generieren $(seq 10)
. Und da seq keine Liste von Buchstaben generieren kann, müssen wir die generierten Zahlen in ASCII konvertieren:
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
druckt:
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}'
gedruckt 3{c..a} 2{c..a} 1{c..a}
. Keine vollständige "Klammererweiterung".
{a..c}1 {a..c}2 {a..c}3
Die Klammererweiterungen in {a..c}{1..3}
werden von links nach rechts erweitert, sodass Sie zuerst a{1..3} b{1..3} c{1..3}
die Buchstaben erhalten und dann mit den Zahlen in kombiniert werden a1 a2 a3 b1 b2 b3 c1 c2 c3
. Um die gewünschte Reihenfolge zu erhalten, müssen Sie den obigen etwas längeren Ausdruck verwenden.
Verwenden einer Schleife:
for n in {1..3}; do printf '%s\n' {a..c}"$n"; done
Dies durchläuft Ihre erste Erweiterung und erweitert dann jedes Zeichen mit dem zweiten.
Wenn Sie die Ausgabe in einer Zeile benötigen, können Sie Folgendes entfernen \n
:
for n in {1..3}; do printf '%s ' {a..c}"$n"; done
Dies gibt Ihnen keinen nachgestellten Zeilenumbruch, aber wenn Sie ihn an einen Befehl oder eine Variable übergeben, sollte dies kein Problem sein.
Dies funktioniert für Ihren einfachen Fall und kann erweitert werden, aber es würde schnell außer Kontrolle geraten. Komplexere Fälle, für die dies nicht funktionieren würde, sind einfach zu konstruieren.
Kehren Sie die Reihenfolge der Klammererweiterungen um und tauschen Sie dann die Zeichen aus:
echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'
Eine einfache Methode wäre die Verwendung von sort (1.2.1.2 bedeutet, dass Sie ein Zeichen an der zweiten Position nehmen und am selben Ort enden).
$ 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
Wenn Sie sie in einer Zeile haben möchten, können Sie tr folgendermaßen verwenden:
$ 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
Geschehen nach folgender Methode
for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"
Ausgabe
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
der Liste auch hinzufügen .