Коли {a, b, c} розгорнуто в bash, коли це не так?


13

Баш сценарій, який містить

for i in {a,b}-{1,2}; do
  echo $i;
done

відбитки

a-1
a-2
b-1
b-2

при виконанні. Це я очікував - у міру розширення {a,b}конструкції.

Однак, коли (інший) скрипт містить

v={a,b}-{1,2}
echo $v

він друкує

{a,b}-{1,2}

що не те, чого я очікував. Я очікував, що він надрукує a-1 a-2 b-1 b-2. Очевидно, що {a,b}конструкція не розширена.

Я можу змусити його розширитись так

v=$(echo {a,b}-{1,2})

На основі цих спостережень у мене є два питання: 1) коли {a,b}конструкція розширена? 2) є $(echo {a,b}-{1,2})кращим способом запустити розширення, коли це потрібно?


1
Принаймні, це відповідає тому, що ви не можете зробити змінну масиву простою =. Наприклад, v=a-1 a-2не вийде.
grochmal

@grochmal - це тому, що ви присвоюєте скалярне значення. v=a-1 a-2означає assign 'a-1' to variable v and run 'a-2' v=(a-1 a-2)призначає масив змінній v. v+=(b-1 b-2)додає до нього.
cas

Відповіді:


15

Посібник Баша говорить, що:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the following
expansions, assignments, and redirections, from left to right.
[...]
4. The  text  after the = in each variable assignment undergoes tilde
   expansion, parameter expansion, command substitution, arithmetic
   expansion, and quote removal before being assigned to the variable.

Розширення дужок немає в списку, тому воно не виконується для призначення v={a,b}-{1,2}. Як згадує @Wildcard, просте розширення v=a-1 v=b-1 ...все одно було б безглуздим.

Крім того, під час виконання echo $v, застосовується таке:

EXPANSION
Expansion is performed on the command line after it has been split
into words. [...]

The order of expansions is: brace expansion; tilde expansion, 
parameter and variable expansion, arithmetic expansion, and command
substitution (done in a left-to-right fashion); word splitting; and
pathname expansion.

Розгортання дужок відбувається перед змінним розширенням, тому дужки, призначені для $vне, розширюються.

Але ви можете робити такі речі:

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar

Розширення з ним $(echo ...)має спрацювати, якщо у вас немає пробілу в рядку, який потрібно розширити, і, отже, не виникне проблем з розщепленням слів. Кращим способом може бути використання змінної масиву, якщо ви можете.

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

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"

5

Цікавий момент. Можливо, корисним є наступний уривок із man bash:

Змінної може бути призначено на затвердження форми

      name = [ значення ]

Якщо значення не задано, змінній присвоюється нульовий рядок. Всі значення зазнають розширення тильди, розширення параметрів і змінних, підміна команд, арифметичне розширення та видалення цитат (див. ДОСЛІДЖЕННЯ нижче).

Зауважте, що розширення дужок НЕ згадується у списку.

Однак це все ще залишає питання, а саме: як оболонка знає, що це присвоєння змінної і, отже, не підлягає розширенню дужок? Або, точніше, де розбирається та кодифікується послідовність розбору, що оболонка визначається для ідентифікації змінних призначень, перш ніж вона обробляє розширення дужки? (Очевидно, як це bashпрацює, але я не знайшов точного рядка документації, що описував би це.)


1
Може, це ? "2. Слова, які не є змінними призначеннями або перенаправленнями, розширені (див. Розширення оболонки)."
Джефф Шаллер

@JeffSchaller, ти маєш рацію. Насправді на це питання найкраще відповісти, просто прочитавши розділ "ПРОСТЕ РОЗШИРЕННЯ КОМАНДИ" ( LESS=+/SIMPLE man bash).
Wildcard

0

Згідно з моїм знанням lil, {a, b, c} розширюється, коли він безпосередньо відлунає або використовується командою, наприклад: mkdir ~ / {a, b, c}, але коли він встановлений змінною, його слід оцінити перед повторюючи його або використовуючи його як аргумент!

u@h:~$ echo {a,b}-{1,2}
a-1 a-2 b-1 b-2
u@h:~$ v={a,b}-{1,2}
u@h:~$ echo $v
{a,b}-{1,2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

оскільки у вас є "a" з послідовністю "b" в алфавітному порядку [az], а "1" з наступним "2" у порядку розкладу [0-9]: ви можете використовувати подвійний період "..", що знаходиться в комах ", "

u@h:~$ echo {a..b}-{1..2}
a-1 a-2 b-1 b-2
u@h:~$ v={a..b}-{1..2}
u@h:~$ echo $v
{a..b}-{1..2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

1
Питання в тому, чому vне було встановлено буквальне рядок "a-1 a-2 b-1 b-2". Або, принаймні, чому не було викинуто жодної помилки, як ви отримаєте, якщо введете команду: v=a-1 v=a-2 v=b-1 v=b-2(на яку ви очікуєте розширення призначення змінної). Це гарне запитання; це насправді не відповідає на це.
Wildcard

@SatoKatsura, що означає "розширення підстановки"? Існує розширення параметрів, розширення імені шляху і розширення дужок - будь-яке з яких ви могли б посилатися, і всі вони різні. Або ви мали на увазі розбиття слів?
Wildcard

0

Призначення змінної в bash не розширює вираз.

Для цього маленького сценарію x буде містити, "*"а не розширення "*":

#!/bin/bash
x=*
echo "$x"

Однак деякі значення розширюються, див. приємна відповідь від ilkkachu.

Вирази розширюються при їх оцінці.

Подобається це:

x=$(echo *)        # <-- evaluation of "*"
echo "$x"

Або так:

x=*
echo $x            # <-- evaluation of $x

Або так:

x=*
eval echo "$x"     # <-- evaluation of `echo *`

Тригери $()є досить поширеними, і я думаю, що це віддано перевагу eval, але найкраще, мабуть, зовсім не викликати оцінку, поки змінна фактично не використовується в команді.

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