명령 및 셸 확장 선언

명령 및 셸 확장 선언

나는 다음과 같은 행동을 우연히 발견했는데 bash, 이는 나에게는 조금 예상치 못한 일이었습니다.

# The following works
$ declare bar=Hello                               # Line 1
$ declare -p bar                                  # Line 2
declare -- bar="Hello"
$ foo=bar                                         # Line 3
$ declare ${foo}=Bye                              # Line 4
$ declare -p bar                                  # Line 5
declare -- bar="Bye"
# The following fails, though
$ declare -a array=( A B C )                      # Line 6
$ declare -p array                                # Line 7
declare -a array=([0]="A" [1]="B" [2]="C")
$ foo=array                                       # Line 8
$ declare -a ${foo}=([0]="A" [1]="XXX" [2]="C")   # Line 9
bash: syntax error near unexpected token `('`
# Quoting the assignment fixes the problem
$ declare -a "${foo}=(A YYY C)"                   # Line 10
$ declare -p array                                # Line 11
declare -a array=([0]="A" [1]="YYY" [2]="C")

쉘 확장으로 인해

  1. 지원 확장
    • 물결표 확장
    • 매개변수 및 변수 확장
    • 산술 확장
    • 프로세스 대체
    • 명령 대체
  2. 분사
  3. 파일 이름 확장자

9행이 토큰으로 분할된 후(그리고 따옴표가 제거된 후) 명령행에서 최종 명령이 실행되기 전에는 9행이 실패할 것으로 예상하지 않습니다.

bash9행이 승인되지 않는 이유는 무엇입니까 ?또는 다른 말로 하면,bash9행 을 실패하게 하고 10행을 성공시키기 위해 처리하는 방식에서 내가 놓치고 있는 것은 무엇입니까 ?

그럼에도 불구하고 인용이 항상 직접적으로 작동하는 것은 아니며 배열 요소가 공백 등이 포함된 문자열인 경우 특별한 주의가 필요합니다.

답변1

너무 길어요 ;dr; 제 생각엔 단지 구문상의 문제일 뿐이고 그 뒤에 뭔가 웅장한 디자인이 있다고 가정해서는 안 됩니다.

bison/yacc를 사용하여 생성된 Bash파서, 그러나 다른 많은 언어(C, Perl 등)와 마찬가지로 "깨끗한" 파서는 아니지만 일부상태변수의 구문과 분리/병렬 parser_state.

이 상태 변수에 포함된 플래그는 입니다 PST_ASSIGNOK. 이 값은 WORD토큰 으로 구문 분석되는 특정 내장 함수가 ASSIGNMENT_BUILTIN해당 플래그에 있을 때 설정됩니다.

이러한 "할당 내장 함수"는 , , localtypeset입니다 .declarealiasexportreadonly

이러한 내장 함수의 오른쪽에 할당한 후 사용하면 파서에게 괄호를 PST_ASSIGNOK토큰의 일부로 처리하도록 지시합니다. WORD그러나 현재 토큰이 실제로 토큰인지 여부를 결정하는 규칙은 변경되지 않습니다.: ${foo}=(...)허용되는 할당이 아니기 때문에 단일 단어로 구문 분석되지 않으며 괄호는 에서처럼 구문 오류를 유발합니다 echo foo(bar).

명령줄을 구문 분석한 후에는 다음과 같습니다.확장하다이며 확장의 일부로 모든 복합 할당( WORD표시됨 W_COMPASSIGN) 이 var=(1 2)수행되고 으로 대체되며 var, 그런 다음 과 같은 내장 함수에 인수로 전달됩니다 declare. 그러나 declare모든 확장 후에 양식의 매개변수를 얻으면 var=(...)양식이 다시 구문 분석되고 확장됩니다.

따라서 변수가 이미 정의되었는지 여부에 따라 . 또는 to varname=foo; declare "$var=(1 2 3)"와 같을 수 있습니다 .declare foo='(1 2 3)'declare foo=(1 2 3)

$ declare 'foo=(1 2 3)'; typeset -p foo
declare -- foo="(1 2 3)"
$ declare foo=(1); typeset -p foo
declare -a foo=([0]="1")
$ declare 'foo=(1 2 3)'; typeset -p foo
declare -a foo=([0]="1" [1]="2" [2]="3")

나는 이 코너 케이스에 의존하는 것이 좋은 생각이 아니라고 생각합니다.

$ declare 'bar=(1 ( )'; typeset -p bar
declare -- bar="(1 ( )"
$ declare bar=(1); typeset -p bar
declare -a bar=([0]="1")
$ declare 'bar=(1 ( )'; typeset -p bar
bash: syntax error near unexpected token `('

관련 정보