Например {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/'
, чтобы изменить это место дляnewline
Примечание_2 : В приведенных выше примерах я использовал подмножества из двух элементов (то есть: {a, b} и {1,2} ) просто для простоты в доказательстве концепции: вы можете использовать подмножества любой конечной длины, а соответствующая команда, будет сопоставимой.
Один вкладыш, который работает в (bash, ksh, zsh) (не все оболочки могут выполнять «расширение скобок» в обратном порядке):
$ 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
в список.