bash에서 {a,b,c}는 언제 확장되고 언제 확장되지 않습니까?

bash에서 {a,b,c}는 언제 확장되고 언제 확장되지 않습니까?

Bash 스크립트에는 다음이 포함되어 있습니다.

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

이것배쉬 매뉴얼설명하다:

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[@]}"

답변2

흥미로운 점. 다음 발췌문이 도움이 될 수 있습니다 man bash.

바꾸다다음 형식의 명령문으로 할당할 수 있습니다.

      이름=[]

만약에지정하지 않으면 변수에 빈 문자열이 할당됩니다. 모두가치물결표 확장, 매개변수 및 변수 확장, 명령 대체, 산술 확장 및 따옴표 제거를 수행합니다(아래 EXPANSION 참조).

가새 확장은 목록에 언급되어 있지 않습니다.

그러나 이것은 여전히 ​​​​질문을 남깁니다. 즉, 이것이 변수 할당이고 따라서 중괄호 확장의 영향을 받지 않는다는 것을 쉘이 어떻게 알 수 있습니까? 또는 더 정확하게는 중괄호 확장을 처리하기 전에 쉘이 변수 할당을 인식하도록 정의되도록 구문 분석 순서가 명확하고 인코딩된 위치입니까? (이것은 분명히 bash이것이 작동하는 방식이지만 이것을 설명하는 정확한 문서 라인을 찾지 못했습니다.)

답변3

내가 아는 바로는 {a,b,c}는 직접 에코되거나 명령과 함께 사용될 때 확장됩니다(예: mkdir ~/{a,b,c} ). 그러나 변수로 설정되면 Evaluate에 있어야 합니다. 그것에 응답하거나 논쟁으로 사용하기 전에!

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"가 10진수 순서로 [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

답변4

Bash에서 변수에 할당해도 표현식이 확장되지 않습니다.

이 작은 스크립트의 경우 x에는 다음 "*"대신 확장이 포함됩니다 "*".

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

그러나 일부 값은 ref로 확장됩니다. ilkkachu의 답변은 훌륭합니다.

평가할 때 표현식이 확장됩니다.

이와 같이:

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

또는 다음과 같습니다:

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

또는 다음과 같습니다:

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

트리거링 $()은 매우 일반적이며 더 우수하다고 생각합니다 eval. 그러나 변수가 실제로 명령에 사용될 때까지 평가를 전혀 트리거하지 않는 것이 가장 좋습니다.

관련 정보