나는 다음과 같은 행동을 우연히 발견했는데 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")
쉘 확장으로 인해
- 지원 확장
- 물결표 확장
- 매개변수 및 변수 확장
- 산술 확장
- 프로세스 대체
- 명령 대체
- 분사
- 파일 이름 확장자
9행이 토큰으로 분할된 후(그리고 따옴표가 제거된 후) 명령행에서 최종 명령이 실행되기 전에는 9행이 실패할 것으로 예상하지 않습니다.
bash
9행이 승인되지 않는 이유는 무엇입니까 ?또는 다른 말로 하면,bash
9행 을 실패하게 하고 10행을 성공시키기 위해 처리하는 방식에서 내가 놓치고 있는 것은 무엇입니까 ?
그럼에도 불구하고 인용이 항상 직접적으로 작동하는 것은 아니며 배열 요소가 공백 등이 포함된 문자열인 경우 특별한 주의가 필요합니다.
답변1
너무 길어요 ;dr; 제 생각엔 단지 구문상의 문제일 뿐이고 그 뒤에 뭔가 웅장한 디자인이 있다고 가정해서는 안 됩니다.
bison/yacc를 사용하여 생성된 Bash파서, 그러나 다른 많은 언어(C, Perl 등)와 마찬가지로 "깨끗한" 파서는 아니지만 일부상태변수의 구문과 분리/병렬 parser_state
.
이 상태 변수에 포함된 플래그는 입니다 PST_ASSIGNOK
. 이 값은 WORD
토큰 으로 구문 분석되는 특정 내장 함수가 ASSIGNMENT_BUILTIN
해당 플래그에 있을 때 설정됩니다.
이러한 "할당 내장 함수"는 , , local
및 typeset
입니다 .declare
alias
export
readonly
이러한 내장 함수의 오른쪽에 할당한 후 사용하면 파서에게 괄호를 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 `('