Na przykład {a..c}{1..3}
rozwija się do a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Jeśli chciałbym wydrukować a1 b1 c1 a2 b2 c2 a3 b3 c3
, czy istnieje analogiczny sposób na zrobienie tego? Jaki jest najprostszy sposób?
źródło
Na przykład {a..c}{1..3}
rozwija się do a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Jeśli chciałbym wydrukować a1 b1 c1 a2 b2 c2 a3 b3 c3
, czy istnieje analogiczny sposób na zrobienie tego? Jaki jest najprostszy sposób?
Mógłbyś:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Co następnie każe powłoce ocenić:
echo {a..c}1 {a..c}2 {a..c}3
W tym konkretnym przypadku uważam, że opcja podana przez Stéphane'a Chazelasa jest najlepsza.
Z drugiej strony, gdy rozwijasz bardziej złożone rzeczy, ta opcja nie skaluje się dobrze. Dzięki temu możesz osiągnąć to samo:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
który zwraca:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Wygląda na trochę bałaganu, ale teraz mam ogromną kontrolę nad kolejnością, zmieniając tylko dwa znaki w powyższym poleceniu; na przykład:
$ echo {a..b}{1..2}{a..b}{1..2}
rozwinie się to do:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Załóżmy, że chcę wszystkich 1
w drugim rozszerzeniu, a następnie 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
Załóżmy, że chcę wszystkich a
w trzecim rozszerzeniu, a następnie 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
Załóżmy, że chcę wszystkich 1
w czwartym rozszerzeniu, a następnie 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
Załóżmy, że chcę wszystko 1a
w środku, potem 1b
, potem 2a
, potem 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
Możesz nawet, równie łatwo, odwrócić dowolną kolejność w powyższych rozszerzeniach, dodając po prostu r
do poprzedniego polecenia; na przykład ostatni:
$ 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
Uwaga_1 : zazwyczaj, jeśli to końcowe rozwinięcie ma być użyte jako lista argumentów, spacja końcowa nie stanowi problemu; ale jeśli chcesz się go pozbyć, możesz na przykład dodać dowolne z powyższych poleceń| sed 's/ $//'
; lub nawet| sed 's/ $/\n/'
, aby zmienić tę końcową przestrzeń dlanewline
Uwaga_2 : W powyższych przykładach użyłem podzbiorów dwóch elementów (tj .: {a, b} i {1,2} ) tylko dla uproszczenia w dowodzie koncepcji: możesz użyć podzbiorów o dowolnej skończonej długości, oraz odpowiednie polecenie byłoby porównywalne.
Jeden linijka, która działa w (bash, ksh, zsh) (nie wszystkie powłoki mogą wykonywać „rozwijanie nawiasu klamrowego” w odwrotnej kolejności):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Alternatywą, która używa eval
(która wciąż jest dla bash, ksh, zsh i może być bardziej tajemnicza) jest:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Aby zrozumieć, co się dzieje, wymienić eval
z echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
Wykonane polecenie (po rozszerzeniu eval) jest w rzeczywistości echo {a..c}1 {a..c}2 {a..c}3
. Który rozwija się tak, jak chcesz / potrzebujesz.
Istnieje kilka powłok bez „rozszerzeń nawiasów”, więc nie można użyć tego dla „wszystkich powłok”. Potrzebujemy pętli (z końcową białą spacją):
$ 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
Jeśli nie musisz dodawać końcowego miejsca:
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
Wydruki
a1 b1 c1 a2 b2 c2 a3 b3 c3
JEŚLI musisz to zrobić dla wielu wartości, musimy użyć czegoś podobnego do rozszerzenia nawiasów, aby wygenerować listę liczb $(seq 10)
. Ponieważ seq nie może wygenerować listy liter, musimy przekonwertować na ascii wygenerowane liczby:
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
drukuje:
a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4
yash -o braceexpand
do listy.yash -o braceexpand -c 'echo {3..1}{c..a}'
drukowane3{c..a} 2{c..a} 1{c..a}
w systemie Linux. Nie pełne „rozszerzenie nawiasu klamrowego”.Rozszerzenia nawiasów
{a..c}{1..3}
są rozszerzane od lewej do prawej, więc najpierw dostajesz,a{1..3} b{1..3} c{1..3}
a następnie litery są łączone z cyframi wa1 a2 a3 b1 b2 b3 c1 c2 c3
. Aby uzyskać pożądaną kolejność, będziesz musiał użyć nieco dłuższego wyrażenia powyżej.źródło
Za pomocą pętli:
Spowoduje to zapętlenie pierwszego rozszerzenia, a następnie rozszerzenie każdej postaci drugim.
Jeśli potrzebujesz danych wyjściowych w jednym wierszu, możesz usunąć
\n
:To nie da ci końca nowej linii, ale jeśli przekazujesz ją do polecenia lub zmiennej, nie powinno to stanowić problemu.
źródło
Działa to w przypadku prostej skrzynki i można ją przedłużyć, ale szybko wymknie się spod kontroli. Bardziej złożone przypadki, dla których to nie zadziała, są łatwe do zbudowania.
Odwróć kolejność rozszerzeń nawiasów, a następnie zamień znaki:
źródło
Jedną z prostych metod byłoby użycie sortowania (1.2,1.2 oznacza, że bierzesz jedną postać z drugiej pozycji i kończysz w tym samym miejscu).
Jeśli chcesz je w jednym wierszu, możesz użyć tr tak:
źródło
Wykonano poniższą metodą
wydajność
źródło
for i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo