bash는 괄호 확장과 명령 그룹화를 어떻게 차별화합니까?


47

{중괄호 확장에 사용할 수 있음을 알았습니다 .

echo {1..8}

또는 명령 그룹화 :

{ls;echo hi}

bash는 어떻게 차이점을 알고 있습니까?


1
훌륭한 질문입니다, +1. {명령의 시작 부분에 표시되면 명령 목록으로 해석되고 그렇지 않으면 중괄호 확장으로 해석되는 것처럼 보이지만 확실하지 않습니다.
Celada

16
{ls;echo hi}합법적이지 않습니다 bash. 여는 중괄호 뒤에 공백이 있어야하고 닫는 앞에 세미콜론이 필요합니다.
PSkocik

답변:


38

단순화 된 이유는 한 문자가 존재하기 때문입니다 space.

중괄호 확장은 인용되지 않은 공백을 처리하지 않습니다.

{...}목록 에는 인용 부호가없는 공백이 필요합니다.

보다 자세한 대답은 쉘이 명령 행을 구문 분석하는 방법 입니다.


명령 행을 구문 분석 (이해)하는 첫 번째 단계는 명령 행을 여러 부분으로 나누는 것입니다.
이러한 부분 (일반적으로 단어 또는 토큰이라고 함)은 명령 줄을 각 메타 문자 에서 링크와 구분하여 생성됩니다 .

  1. 고정 메타 문자 세트 (SPACE, TAB, NEWLINE,;, (,), <,>, | 및 &)로 구분 된 토큰으로 명령을 분할합니다. 토큰 유형에는 단어, 키워드, I / O 리디렉터 및 세미콜론이 포함됩니다.

메타 문자 : spacetabenter;,<>|&.

분할 후 단어는 (쉘에서 이해되는) 유형일 수 있습니다.

  • 명령 사전 서명 : LC=ALL ...
  • 명령 LC=ALL echo
  • 인수 LC=ALL echo "hello"
  • 리디렉션 LC=ALL echo "hello" >&2

버팀대 확장

"괄호 문자열"(공백 또는 메타 문자가없는)이 단일 단어이고 (위에서 설명한대로) 인용되지 않은 경우에만 "중괄호 확장"의 후보입니다. 내부 구조에 대한 추가 점검은 나중에 수행됩니다.

따라서, 이는 : {ls,-l}될 "가새 확장"자격 ls -l으로하거나, first word또는 argument(zsh을는 떠들썩한 파티에서 다르다).

$ {ls,-l}            ### executes `ls -l`
$ echo {ls,-l}       ### prints `ls -l`

그러나 이것은 : {ls ,-l}. 배쉬에서 분할합니다 space및 두 단어로 라인을 구문 분석 : {ls하고 ,-l}있는이 트리거 command not found(인수가 ,-l}손실됩니다)

 $ {ls ,-l}
 bash: {ls: command not found

귀하의 라인 : {ls;echo hi}때문에의 "중괄호 확장"가되지 않습니다 메타 문자 ;space.

다음 세 부분으로 나뉩니다. {ls새 명령 : echo hi}. ;트리거가 새 명령의 시작을 트리거 한다는 것을 이해하십시오 . 명령 {ls을 찾을 수 없으며 다음 명령이 인쇄됩니다 hi}.

$ {ls;echo hi}
bash: {ls: command not found
hi}

다른 명령 뒤에 배치되면 어쨌든 다음에 새 명령이 시작됩니다 ;.

$ echo {ls;echo hi}
{ls
hi}

명부

"복합 명령"중 하나는 "중괄호 목록"(내 단어) { list; }입니다.
보시다시피 공백과 닫는 것으로 정의됩니다 ;.
공간과는 ;모두 있기 때문에 필요 {하고 }"예약 된 단어 ".

따라서 단어로 인식 되려면 메타 문자로 둘러싸 야합니다 (거의 항상 :) space.

링크 된 페이지 의 포인트 2에 설명 된대로

  1. 각 명령의 첫 번째 토큰을 검사하여 ...., {또는 ()인지 확인하십시오. 그러면 명령이 실제로 복합 명령입니다.

귀하의 예 : {ls;echo hi}목록이 아닙니다.

;뒤에 닫히고 하나 이상의 공백 이 필요합니다 {. 마지막 }은 닫는 것으로 정의됩니다 ;.

이것은 목록 { ls;echo hi; }입니다. 그리고 이것은 { ls;echo hi;}또한 (일반적으로 덜 사용되지만 유효합니다) (@choroba의 도움에 감사드립니다).

$ { ls;echo hi; }
A-list-of-files
hi

그러나 명령에 대한 인수 (쉘은 차이점을 알고 있음)로 오류를 트리거합니다.

$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'

그러나 쉘이 구문 분석하고 있다고 믿는 것에주의하십시오.

$ echo { ls;echo hi;
{ ls
hi

2
이것은 bash 파서의 작동 방식을 실제로 알려주기 때문에 실제로 가장 좋은 대답입니다! 그리고 자세한 설명과 함께!
lovespring

2
;와 사이에 공백이 필요하지 않습니다 }. { ls;}세미콜론은 이미 메타 문자로 작동합니다.
choroba

1
@lovespring 고마워요, 글쓰기에 시간을 투자했습니다. 유용하다는 것을 알게되어 기쁩니다. 다시 한 번 감사합니다.

훌륭한 기사, 참고에 감사드립니다
Edward Torvalds

16

블록 {은 쉘 키워드이므로 공백으로 다음 단어와 구분해야하며 중괄호 확장에는 공백이 없어야합니다 (공백 확장 공백을 사용해야하는 경우에는 이스케이프해야합니다. echo {\ ,a}{b,c}).

명령 시작시 괄호 확장을 사용할 수 있습니다.

{ls,.}  # expands to "ls ."

확장 전에 그룹화 명령 구문 분석이 발생하므로이를 사용하여 블록으로 확장 할 수 없습니다.

echo {'{ ls','.;}'}  # { ls .;}
{'{ ls','.;}'}       # bash: { ls: No such file or directory

5

명령 줄의 구문을 확인하여 알 수 있습니다. 같은 식으로 echo echo, 표현식 에서 첫 번째 에코는 명령으로 처리되고 두 번째 에코는 첫 번째 에코의 매개 변수로 처리되어야합니다.

bash에서는 { cmd; }공백과 세미콜론이 있어야 하므로 매우 간단 합니다. 그러나 예를 들어 zsh에서는 필요하지 않지만 여전히 {}셸 컨텍스트를 분석 하여 내용으로 수행해야 할 작업을 알 수 있습니다.

다음을 고려하세요:

alias 1..3=date
{ 1..3; }    #in bash
{1..3}       #in zsh

둘 다 현재 날짜를 반환하지만

echo {1..3}

1 2 3shell은 {}command의 인수를 알고 있기 때문에 반환 되므로 echo확장해야합니다.


{따옴표없는 공간이 뒤에 오는 것은 bash에서 괄호 확장을 시작하지 않습니다.
choroba

@choroba 그렇습니다 {. 쉘이 전체 명령 행을 공백으로 분할하므로 인용되지 않은 공간은 어디에도있을 수 없습니다.
jimmij

0

먼저 복합 중괄호는 단어 자체와 명령 줄의 첫 번째 단어 여야합니다.

echo { these braces are just words }

둘째, 개별 괄호는 특별하지 않습니다 (위에서 볼 수 있듯이). 빈 괄호도 특별하지 않습니다 :

echo {} # just the token {}: familiar from the find command

쉼표가없는 것도 그 자체입니다

echo {abc} # just {abc}

여기에서 작업이 시작됩니다.

echo {a,b} # braces disappear, a b results.

따라서 기본적으로 중괄호 확장을 시작하려면 하나 이상의 단어 (공백에서 필드로 분리되지 않음)가 필요합니다. 내부 {...}에는 적어도 하나의 쉼표가있는 내부 인스턴스가 하나 이상 있습니다.

이것은 명령 행에서 첫 번째 단어 있습니다.

{ls,-l} .   # just "ls -l ."
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.