Наприклад, {a..c}{1..3}
розширюється до a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Якщо я хотів надрукувати a1 b1 c1 a2 b2 c2 a3 b3 c3
, чи є аналогічний спосіб це зробити? Який найпростіший спосіб?
Наприклад, {a..c}{1..3}
розширюється до a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Якщо я хотів надрукувати a1 b1 c1 a2 b2 c2 a3 b3 c3
, чи є аналогічний спосіб це зробити? Який найпростіший спосіб?
Відповіді:
Ви можете зробити:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Що потім говорить оболонці оцінити:
echo {a..c}1 {a..c}2 {a..c}3
У цьому конкретному випадку я думаю, що варіант, запропонований Стефаном Шазеласом, є найкращим.
З іншого боку, коли ви розгортаєте більш складні речі, цей параметр не дуже масштабується. Таким чином, ви можете досягти цього і з цим:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
який повертає:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Здається, трохи безладно, але зараз я маю величезний контроль у порядку, просто змінюючи два символи в команді, що знаходиться вище; наприклад:
$ echo {a..b}{1..2}{a..b}{1..2}
це розшириться до:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Припустимо, я хочу все 1
у другому розширенні, а потім 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
Припустимо, я хочу все a
в третьому розширенні, а потім 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
Припустимо, я хочу, щоб все було 1
в четвертому розширенні, а потім 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
Припустимо, я хочу все 1a
посередині, потім 1b
, потім 2a
, потім 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
Ви можете навіть так само легко повернути будь-який порядок у розширеннях вище, просто додавши r
до попередньої команди; наприклад, останній:
$ 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
Примітка_1 : зазвичай, якщо це остаточне розширення буде використано в якості списку аргументів, пробіл не є проблемою; але якщо ви хочете позбутися від нього, ви можете додати, наприклад, до будь-якої з команд вище, наприклад| sed 's/ $//'
; або навіть| sed 's/ $/\n/'
змінити цей простір для anewline
Примітка_2 : У наведених вище прикладах я використовую підмножини з двох елементів (тобто: {a, b} і {1,2} ) просто для простоти доказу поняття: ви можете використовувати підмножини будь-якої кінцевої довжини, а відповідна команда, була б порівнянна.
Один вкладиш, який працює в (bash, ksh, zsh) (не всі оболонки можуть робити "розширення Brace" у зворотному порядку):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Альтернативою, що використання eval
(яке все-таки є bash, ksh, zsh і може бути більш виразним):
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Щоб зрозуміти, що відбувається, замініть eval
на echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
Команда, що виконується (після розширення eval), є насправді echo {a..c}1 {a..c}2 {a..c}3
. Який розширюється як хочеш / потребуєш.
Існує кілька оболонок без "дугових розширень", тому використовувати їх для "всіх оболонок" неможливо. Нам потрібна петля (з білим пробілом):
$ 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
Якщо у вас не повинно бути додано пробілів:
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
Друкує
a1 b1 c1 a2 b2 c2 a3 b3 c3
Якщо вам потрібно зробити це для багатьох значень, нам потрібно використовувати щось подібне до розширення дужок, щоб створити список чисел $(seq 10)
. І оскільки seq не може генерувати список букв, нам потрібно перетворити на ascii створені числа:
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
відбитки:
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}'
друкується 3{c..a} 2{c..a} 1{c..a}
в Linux. Не повне "розширення дужок".
{a..c}1 {a..c}2 {a..c}3
Розширення в {a..c}{1..3}
дужках розширено ліворуч праворуч, тому ви спочатку отримуєте, a{1..3} b{1..3} c{1..3}
а потім букви комбінуються з цифрами в a1 a2 a3 b1 b2 b3 c1 c2 c3
. Щоб отримати бажане замовлення, вам доведеться скористатись трохи довшим виразом вище.
Використання циклу:
for n in {1..3}; do printf '%s\n' {a..c}"$n"; done
Це пройде цикл вашого першого розширення, а потім розгорне кожен символ з другим.
Якщо вам потрібен вихід у одному рядку, ви можете видалити \n
:
for n in {1..3}; do printf '%s ' {a..c}"$n"; done
Це не дасть вам зворотного нового рядка, але якщо ви передаєте його команді чи змінній, це не повинно бути проблемою.
Це працює для вашого простого випадку і може бути розширено, але це швидко вийде з рук. Складніші випадки, для яких це не вдасться, легко побудувати.
Поверніть порядок розширень дужок, а потім поміняйте символи:
echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'
Одним з простих методів було б використання сортування (1.2,1.2 означає, що ви берете один символ на другій позиції і закінчуєте на тому самому місці).
$ 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
Якщо ви хочете, щоб вони були в одному рядку, ви можете використовувати tr так:
$ 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
Виконано методом нижче
for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"
вихід
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
до списку.