Bash의 중첩된 중괄호 확장의 미스터리

Bash의 중첩된 중괄호 확장의 미스터리

이것:

$ echo {{a..c},{1..3}}

다음을 생성합니다.

a b c 1 2 3

좋은데 설명하기가 어렵네요

$ echo {a..c},{1..3}

주어진

a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3

이것이 어딘가에 문서화되어 있습니까? 이것배시 참조이에 대한 언급은 없습니다(비록 그것을 사용하는 예가 있지만).

답변1

자, 한 번에 한 레이어씩 풀어보겠습니다.

X{{a..c},{1..3}}Y

X{a..c}Y X{1..3}Y는 (존재를 통해 ) 로 확장되는 것으로 기록되고 X{A,B}Y, 그 자체는 으로 확장되는 것으로 기록됩니다.XA XBA{a..c}B{1..3}XaY XbY XcY X1Y X2Y X3Y

중첩될 수 있다는 점을 문서화할 가치가 있을 것입니다(첫 번째 항목은 중첩 }되지 않음).폐쇄{예를 들어 첫 번째 것).

나는 쉘이 이 문제를 해결하기 위해 선택할 수 있다고 생각합니다내부에먼저 중괄호는 각 끝에서 차례로 다음과 같이 작동합니다 }.

  1. X{{a..c},{1..3}}
  2. X{a,{1..3}}Y X{b,{1..3}}Y X{c,{1..3}}Y

    (즉 , , where is 및 is A{a..c}B로 확장됨 )AaB AbB AcBAX{B,{1..3}Y

  3. X{a,1}Y X{a,2}Y X{a,3}Y X{b,1}Y X{b,2}Y X{b,3}Y X{c,1}Y X{c,2}Y X{c,3}Y

  4. XaY X1Y XaY Xa2...

csh그러나 나는 이것이 특히 더 직관적이거나 유용하다고 생각하지 않습니다(예를 들어 주석에서 Kevin 의 예를 참조하십시오). 확장이 수행되는 순서에 대해 여전히 모호함이 있습니다. 70년대 확장에 비해 {1..3}나중에(1995)에서 형태가 만들어 zsh졌지만 {a..c}이후(2004)에서 bash)가 만들어졌습니다.

참고하세요 csh(처음부터2BSD(1979) 매뉴얼 페이지)은 중괄호 확장이 중첩될 수 있다는 사실을 문서화하지만 중첩된 중괄호 확장이 어떻게 확장되는지 명시적으로 명시하지는 않습니다. 하지만 넌 할수있어csh1979년 코드를 보세요그것이 어떻게 이루어졌는지 보세요. 중첩을 명시적으로 처리하는 방법과 외부 중괄호부터 시작하여 구문 분석하는 방법을 확인하세요.

{a..c},{1..3}어쨌든 확장의 영향이 무엇인지 잘 모르겠습니다 . 여기서 ,연산자는 중괄호로 확장되지 않으므로(중괄호 안에 있지 않기 때문에) 일반 문자로 처리됩니다.

답변2

그것은 짧은 대답입니다. 첫 번째 표현식에서는 쉼표가 구분 기호로 사용되므로 중괄호 확장은 단지 두 개의 중첩된 하위 표현식을 연결하는 것입니다. 두 번째 표현식에서는 쉼표 자체가 단일 문자 하위 표현식으로 처리되므로 product 표현식은형태.

당신이 놓치고 있는 것은 버팀대 확장을 수행하는 방법에 대한 정의입니다. 다음은 세 가지 참고 자료입니다.

아래는 좀 더 자세한 설명입니다.


이 표현식의 결과를 비교합니다.

$ echo {{a..c},{1..3}}
a b c 1 2 3

이 표현식의 결과:

$ echo {a..c},{1..3}
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3

설명하기 어렵다고 하더군요. 즉 직관에 어긋난다는 뜻이죠. 빠진 것은 중괄호 확장을 처리하는 방법에 대한 공식적인 정의입니다. 당신은 눈치 챘다배쉬 매뉴얼완전한 정의는 제공되지 않습니다.

조금 검색했지만 누락된(완전하고 형식적인) 정의도 찾을 수 없습니다. 그래서 소스코드를 보러 갔습니다.

소스에는 몇 가지 유용한 설명이 포함되어 있습니다. 먼저, 버팀대 확장 알고리즘에 대한 높은 수준의 개요입니다.

Basic idea:

Segregate the text into 3 sections: preamble (stuff before an open brace),
postamble (stuff after the matching close brace) and amble (stuff after
preamble, and before postamble).  Expand amble, and then tack on the
expansions to preamble.  Expand postamble, and tack on the expansions to
the result so far.

따라서 중괄호 확장 마크업의 형식은 다음과 같습니다.

<PREAMBLE><AMBLE><POSTAMBLE>

확장의 주요 진입점은 brace_expand다음과 같이 설명되는 함수입니다.

Return an array of strings; the brace expansion of TEXT.

따라서 brace_expand함수는 중괄호 확장 표현식을 나타내는 문자열을 가져와 확장된 문자열 배열을 반환합니다.

이 두 가지 관찰을 결합하면 서문이 문자열 목록으로 확장되고 각 문자열이 서문에 연결되는 것을 볼 수 있습니다. 그런 다음 포스트앰블은 문자열 목록으로 확장되고 포스트앰블 목록의 각 문자열은 프리앰블/프리앰블 목록의 각 문자열에 연결됩니다(즉, 두 목록의 곱을 형성함). 그러나 이것은 프리앰블과 포스트앰블을 처리하는 방법을 설명하지 않습니다. 다행히도 이에 대한 리뷰도 있습니다. 이 동기화 코드는 함수 expand_amble정의 앞에 다음 주석이 붙는 함수에 의해 처리됩니다.

Expand the text found inside of braces.  We simply try to split the
text at BRACE_ARG_SEPARATORs into separate strings.  We then brace
expand each slot which needs it, until there are no more slots which
need it.

코드의 다른 부분에서는 BRACE_ARG_SEPARATOR가 쉼표로 정의되어 있음을 알 수 있습니다. 이는 amble이 쉼표로 구분된 문자열 목록이며 그 중 일부는 중괄호로 확장된 표현식일 수도 있음을 분명히 보여줍니다. 그런 다음 이러한 문자열은 배열로 구성됩니다. 마지막으로 expand_ambleafter 를 호출한 후 brace_expand사후 동기화 코드에서 함수가 재귀적으로 호출되는 것도 확인할 수 있습니다 . 이는 알고리즘에 대한 완전한 설명을 제공합니다.

이 결과를 확인하는 몇 가지 다른 (비공식) 참고 자료가 있습니다.

참고로 를 참조하세요배쉬 해커 위키. 이 섹션은 다음과 같습니다.결합 및 중첩귀하의 질문에 정확히 대답하지는 않지만 페이지에는 중괄호 확장의 구문/구문이 제공되어 귀하의 질문에 대답한다고 생각합니다. 구문은 다음 패턴으로 제공됩니다.

{string1,string2,...,stringN}

{<START>..<END>}

<PREAMBLE>{........}

{........}<POSTSCRIPT>

<PREAMBLE>{........}<POSTSCRIPT>

구문 분석 설명은 다음과 같습니다.

중괄호 확장은 임의의 문자열을 생성하는 데 사용됩니다. 지정된 문자열은 생성하는 데 사용됩니다.가능한 모든 조합선택적으로 주변 서문과 후기 스크립트를 포함합니다.

또 다른 참고 사항은 다음을 확인하세요.Bash 초보자 가이드, 여기에는 다음이 포함됩니다.

Brace expansion is a mechanism by which arbitrary strings may be generated. Patterns to be brace-expanded take the form of an optional PREAMBLE, followed by a series of comma-separated strings between a pair of braces, followed by an optional POSTSCRIPT. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right.

따라서 중괄호 확장 표현식을 구문 분석하기 위해 왼쪽에서 오른쪽으로 이동하여 각 표현식을 확장하고 연속적인 제품을 형성합니다(문자열 연결 작업과 반대).

이제 첫 번째 표현을 고려해 보겠습니다.

{{a..c},{1..3}}

Bash Hacker's Wiki 언어에서 이는 첫 번째 형식과 일치합니다.

{string1,string2,...,stringN}

여기서 N=2, string1={a..c}string2={1..3}- 내부 중괄호 확장을 먼저 수행하며 각 확장은 다음과 같은 형식을 갖습니다 {<START>..<END>}. 또는 이것이 서문만 포함하는 중괄호 확장 표현(서문 또는 후문 없음)이라고 말할 수 있습니다. amble은 쉼표로 구분된 목록이므로 한 번에 한 슬롯씩 목록을 살펴보고 필요한 경우 추가 확장을 수행합니다. 인접 표현식이 없으므로(쉼표를 구분 기호로 사용함) 곱이 형성되지 않습니다.

다음으로 두 번째 표현을 살펴보겠습니다.

{a..c},{1..3}

Bash Hacker's Wiki의 언어에서 이 표현은 다음 형식과 일치합니다.

{........}<POSTSCRIPT>

여기서 postscript는 하위 표현식입니다 ,{1..3}. 또는 이 표현에는 서문( {a..c})과 후문( ) 이 있다고 말할 수 있습니다 ,{1..3}. 프리앰블은 목록으로 확장되며 a b c, 각 목록은 포스트앰블 확장의 각 문자열과 연결됩니다. 포스트앰블은 재귀적으로 처리됩니다. 프리앰블은 ,이고 프리앰블은 입니다 {1..3}. 이것은 목록으로 확장되었습니다 ,1 ,2 ,3. a b c그런 다음 두 목록이 ,1 ,2 ,3결합되어 제품 목록을 형성합니다 a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3.

이러한 표현식이 어떻게 구문 분석되는지에 대한 의사 대수적 설명을 제공하는 것이 도움이 될 수 있습니다. 여기서 대괄호 "[]"는 배열을 나타내고, "+"는 배열 연결을 나타내고, "*"는 데카르트 곱(연결과 반대)을 나타냅니다.

첫 번째 표현식을 확장하는 방법은 다음과 같습니다(한 줄에 한 단계).

{{a..c},{1..3}}
{a..c} + {1..3}
[a b c] + [1 2 3]
a b c 1 2 3

두 번째 표현식이 확장되는 방법은 다음과 같습니다.

{a..c},{1..3}
{a..c} * ,{1..3}
[a b c] * [,1 ,2 ,3]
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3

답변3

내 이해는 다음과 같습니다.

내부 중괄호는 항상 그렇듯이 먼저 구문 분석됩니다.

{{a..c},{1..3}}

입력하다

{a,b,c,1,2,3}

,중괄호 안에 있기 때문에 중괄호 요소만 분리합니다.

하지만 이 경우에는

{a..c},{1..3}

즉, 이는 ,중괄호 안에 있지 않습니다. 즉, 중괄호가 양쪽에 정렬되도록 하는 일반 문자입니다.

관련 정보