Застосувати розширення дужок у "зворотному порядку"


21

Наприклад, {a..c}{1..3}розширюється до a1 a2 a3 b1 b2 b3 c1 c2 c3.

Якщо я хотів надрукувати a1 b1 c1 a2 b2 c2 a3 b3 c3, чи є аналогічний спосіб це зробити? Який найпростіший спосіб?

Відповіді:


30

Ви можете зробити:

$ 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

10

У цьому конкретному випадку я думаю, що варіант, запропонований Стефаном Шазеласом, є найкращим.

З іншого боку, коли ви розгортаєте більш складні речі, цей параметр не дуже масштабується. Таким чином, ви можете досягти цього і з цим:

$ 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} ) просто для простоти доказу поняття: ви можете використовувати підмножини будь-якої кінцевої довжини, а відповідна команда, була б порівнянна.


5

баш, кш, зш

Один вкладиш, який працює в (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до списку.
Стефан Шазелас

@ StéphaneChazelas Я не впевнений, що повинен. Команда yash -o braceexpand -c 'echo {3..1}{c..a}'друкується 3{c..a} 2{c..a} 1{c..a}в Linux. Не повне "розширення дужок".
Ісаак

3
{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. Щоб отримати бажане замовлення, вам доведеться скористатись трохи довшим виразом вище.


Якби ви хотіли зробити це для великого діапазону "чисел", це вже не було б практично.
RUBEN GONÇALO MOROUÇO

3
@ RUBENGONÇALOMOROUÇO Ні, це не було б, і якщо ви робите це для великого діапазону чисел, я б запропонував використовувати альтернативний підхід, як подвійний цикл. Це працювало б для багатьох тисяч комбінацій, тоді як дужки розширюють мій тригер "аргумент надто довгий" у певних контекстах.
Kusalananda

2

Використання циклу:

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

Це не дасть вам зворотного нового рядка, але якщо ви передаєте його команді чи змінній, це не повинно бути проблемою.


1
Чому стільки голосів вниз за рішення циклу?
Ісаак

Думаю, я, мабуть, неправильно прочитав питання. Оновлено
Jesse_b

2

Це працює для вашого простого випадку і може бути розширено, але це швидко вийде з рук. Складніші випадки, для яких це не вдасться, легко побудувати.

Поверніть порядок розширень дужок, а потім поміняйте символи:

echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'

@muru: На жаль. Виправлено. Спасибі.
Призупинено до подальшого повідомлення.


0

Одним з простих методів було б використання сортування (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

-2

Виконано методом нижче

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
Джефф Шаллер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.