투표율이 높은 원 라이너에 중첩 된 큰 따옴표


20

3.5K 이상의 투표가 포함 된 StackOverflow 답변DIR 에는 현재 bash 스크립트의 디렉토리에 할당 할 수 있는 이 한 줄짜리 기능이 있습니다.

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

중첩 된 큰 따옴표에 의아해합니다. 내가 알 수있는 한 다음 조각은 큰 따옴표로 묶습니다.

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

... 그리고 오른쪽에있는 다른 모든 =(즉, $( dirname)) 인용 부호로 둘러싸입니다. 즉, 두 번째, 네 번째 및 여섯 "번째 "문자는 각각 첫 번째, 세 번째 및 다섯 번째 문자를 "닫습니다" 라고 가정합니다 .

큰 따옴표가 "${BASH_SOURCE[0]}"무엇 을 달성 하는지 이해 하지만 다른 두 따옴표의 목적은 무엇입니까?

반면에 (그리고 높은 투표 점수에도 불구하고) 위의 스 니펫이 잘못된 경우 명목상의 의도를 달성하는 올바른 방법은 무엇입니까?

( 공칭 의도로 나는 의미합니다 :을 반환 한 디렉토리에 pwd처음 cd-ing 한 후 반환 된 값을 수집하고 하위 셸에서 -ing을 dirname "${BASH_SOURCE[0]}"수행 하여 상위 셸의 값을 변경 하지 마십시오 ).cd$PWD


1
$ (...)의 기능 때문입니다 $( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... ).
Olivier Dulac 2016 년

도커 설치 스크립트로 인해 여기에 왔습니다. 배포판의 이름을 찾으려면 :lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer

줄의 공백은 필요하지 않습니다. DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"작동합니다.
David Tonhofer

답변:


12

당신의 퍼즐은 bash(그리고 일반적으로 쉘) 입력을 어떻게 파싱 했는지에 대해 옳지 않습니다 . 에서:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

먼저 큰 따옴표가 큰 따옴표 안에 나타날 수 있으므로 bash할당의 오른쪽을 하나의 긴 문자열로 구문 분석하십시오 .$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

그런 다음 bash명령 대체 구문 분석을 시작하십시오. 열기 괄호 다음에 괄호로 묶는 모든 문자가 명령 대체 내에서 명령을 구성하는 데 사용되므로 다음과 같은 이점이 있습니다.

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

쉘은 복합 명령을 계속 구문 분석하고 두 부분으로 나눕니다.

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • 암호

그런 다음 동일한 구문 분석 규칙을 적용 cd "$( dirname "${BASH_SOURCE[0]}" )"하지만 이번에는 큰 따옴표는 중복되지 않지만 의미가 있습니다. 의 결과로 필드가 분할되는 것을 방지 $( dirname "${BASH_SOURCE[0]}" )하고 확장합니다 ${BASH_SOURCE[0]}(가장 큰 따옴표와 달리 RHS는 변수 할당의 RHS에서 필요하지 않습니다split+glob ).


이 규칙 은 모든 POSIX 쉘에서 명령 대체에 적용됩니다 . POSIX 사양의 토큰 인식 섹션 에서 더 자세한 퍼즐을 읽을 수 있습니다 .


21

안에 들어가면 $(...)인용문이 처음부터 다시 시작됩니다.

즉, "..."$(...)깡통 둥지 서로 내. 프로세스 대체 $(...)에는 하나 이상의 완전한 큰 따옴표로 묶인 문자열이 포함될 수 있습니다 . 또한 큰 따옴표로 묶인 문자열에는 하나 이상의 완전한 프로세스 대체 가 포함될 수 있습니다 . 그러나 인터레이스하지 않습니다. 따라서 프로세스 대체 내부에서 시작하는 큰 따옴표로 묶인 문자열은 절대로 그 외부로 확장되거나 그 반대로 확장되지 않습니다.

따라서 다음을 고려하십시오.

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

내부 $(...)는 다음과 같습니다.

dirname "${BASH_SOURCE[0]}"

위의 ${BASH_SOURCE[0]}큰 따옴표입니다. 큰 따옴표를 $(...)결정할 때 큰 따옴표 또는 작은 따옴표 는 관련이 없습니다 ${BASH_SOURCE[0]}.

외부 $(...)에는 다음 이 포함됩니다.

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

여기에서 표현식 $( dirname "${BASH_SOURCE[0]}" )은 큰 따옴표로 묶습니다. 외부에 따옴표가 있다는 사실 $(...)은 내부에 무엇이 있는지 고려할 때 관련이 없습니다. 내부에 따옴표가 있다는 사실 $(...)도 관련이 없습니다.

큰 따옴표가 일치하는 방법은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오


무슨 소리 야 irrelevant? 대부분의 괄호를 제외하고 다른 모든 괄호에는 고유 한 의미가 있습니다.
cuonglm 2016 년

4
그리고 이것이 백틱을 사용해서는 안되는 이유입니다. 인용 규칙은 매우 이상하고 직관적이지 않습니다.
와일드 카드

" $(...)보다 꽉 묶는 "문장 "..."은 의미가 없습니다. 그들은 연산자를 고치지 않으며 그들 사이에 계층 구조가 없습니다 (만약 있다면 따옴표는 괄호 안에 있거나 괄호는 따옴표 안에 있지는 않지만 그렇지 않습니다). 기술적 인 용어는 그것 $(…)"…"둥지입니다.
Gilles 'SO- 악마 그만해'

@Gilles 아주 좋아. 나는 그 개념을 더 잘 포착하기를 희망하면서 다시 말 하였다.
John1024
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.