명령 및 셸 확장 선언

명령 및 셸 확장 선언

나는 우연히 다음과 같은 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행이 실패할 것으로 예상하지 않았습니다.

bash9행을 허용하지 않는 이유는 무엇입니까 ?아니면 다르게 말하면,bash9행이 실패하게 만들고 10행을 성공하게 만드는 방식에서 내가 놓치고 있는 것은 무엇입니까 ?

어떤 경우든 인용이 항상 간단하게 작동하는 것은 아니며 배열 요소가 공백 등이 포함된 문자열인 경우 특별한 주의가 필요합니다.

답변1

tl;dr; 나는 이것이 단지 구문상의 문제일 뿐이라고 생각하며 그 뒤에 어떤 웅장한 디자인이 있다고 가정해서는 안 됩니다.

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

해당 상태 변수에 유지되는 플래그는 입니다 PST_ASSIGNOK. 이는 토큰으로 구문 분석된 일부 내장 기능이 해당 플래그에 WORD있을 때 설정됩니다 .ASSIGNMENT_BUILTIN

이러한 "할당 내장"은 local, typeset, declare, aliasexport입니다 readonly.

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

명령줄이 구문 분석된 후에는 다음과 같습니다.퍼지는, 그리고 확장의 일부로, like WORD로 표시된 모든 복합 할당이 수행되고 로 대체되며 , 그런 다음 내장 like에 인수로 전달됩니다 . 그러나 모든 확장 후에 가 형식의 인수를 받으면 자체적으로 다시 구문 분석하고 확장합니다.W_COMPASSIGNvar=(1 2)vardeclaredeclarevar=(...)

따라서 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 `('

관련 정보