Bash는 동적 배열 이름을 사용할 수 없습니다(하지만 이해합니다).

Bash는 동적 배열 이름을 사용할 수 없습니다(하지만 이해합니다).

Bash에서 스크립트를 작성 중이고 루프 내부에 배열을 선언해야 하므로 다음과 같이 합니다.

variable=suffix
declare -a prefix_$variable='(item1 item2)'

그러면 "prefix_$variable"을 사용할 수 있어야 하는데 사용할 수 없어 실패합니다.

그러나 선언은 작동합니다. 선언 후에 echo ${prefix_sufix[@]}항목을 에코하기 때문입니다. 유일한 문제는 배열 이름을 직접 작성해야 한다는 것입니다.

이 예를 살펴보십시오.

mint@ubuntu ~ $ variable=suffix
mint@ubuntu ~ $ declare -a prefix_$variable='(item1 item2)'
mint@ubuntu ~ $ echo ${prefix_suffix[@]}
item1 item2
mint@ubuntu ~ $ echo ${prefix_$variable[@]}
bash: ${prefix_$variable[@]}: bad substitution
mint@ubuntu ~ $ prefix_$variable[2]='none'
bash: prefix_suffix[2]=none: command not found

오류 메시지에 "prefix_suffix"라고 적혀 있기 때문에 변수 이름을 이해하고 있지만 올바르게 실행되지 않는다는 점을 분명히 알 수 있으므로 이는 의미가 없습니다.

어떻게 되어가나요? 이 문제를 어떻게 해결할 수 있나요?

결과에 아무런 변화 없이 마지막 부분을 "prefix_${variable}"[2]='none', prefix_${variable}[2]='none', , 으로 다시 작성해 보았습니다 .$(prefix_$variable[2]='none')

답변1

해결책은 nameref를 사용하는 것입니다.

$ variable=suffix
$ declare -n shortname=prefix_$variable
$ declare -a prefix_$variable='(item1 item2)'
$ echo ${prefix_suffix[@]}
item1 item2
$ echo "${shortname[@]}"
item1 item2
$ shortname[2]='none'
$ echo ${prefix_suffix[@]}
item1 item2 none

답변2

"여기에서 무슨 일이 일어나고 있는지"는 쉘 작업이며 기능이 마술처럼 발생하지 않습니다. bash를 포함한 모든 POSIX 쉘에는 다음이 필요합니다.결정된 시퀀스를 실행유연성이 제한적입니다.

abc_def=heffalump

처음 토큰으로 파싱하면 ASSIGNMENT_WORD 이고 복합명령어에는 포함되지 않으므로 다음과 같이 처리된다.간단한 명령: 할당을 저장하고 나머지를 확장하고(비어 있으므로 아무 일도 일어나지 않음) 할당이 확장되고(아무것도 하지 않음) 명령 이름(또는 인수)이 없으므로 현재 환경의 변수에 값이 다시 할당됩니다. (하위 쉘이 아닌) "메인" 쉘이라고 하며 프로그램 실행을 시도하지 않습니다.

abc_$xyz=heffalump

abc_$xyz유효하지 않은 변수 이름(숫자가 아닌 문자로 시작하는 문자, 숫자 및 밑줄만 가능)은 ASSIGNMENT_WORD로 구문 분석될 수 있거나 일반 bash가 후자를 수행하기 때문입니다 . 결과 :

  1. 쉘 구문 규칙에 따라 변수 할당 또는 리디렉션으로 식별된 단어는 3단계와 4단계의 처리를 위해 저장됩니다.

할당이나 리디렉션이 해결되지 않으므로 아무 작업도 수행되지 않습니다.

  1. 변수 할당이나 리디렉션이 아닌 단어는 확장되어야 합니다. 확장 후 남은 필드가 있는 경우 첫 번째 필드는 명령 이름으로 처리되어야 하며 나머지 필드는 명령에 대한 인수입니다.

단어는 (say) 로 확장됩니다 abc_eeyore=heffalump. 단어는 하나만 있으며 명령 이름으로 처리됩니다.

  1. 리디렉션은 리디렉션에 설명된 대로 수행되어야 합니다.

리디렉션이 없으므로 아무 작업도 수행되지 않습니다.

  1. 물결표 확장, 매개변수 확장, 명령 대체, 산술 확장 및 따옴표 제거를 할당하기 전에 모든 변수 할당을 확장해야 합니다.

작업이 없으므로 아무것도 수행되지 않습니다.

간단한 명령이 명령 이름과 선택적 인수 목록을 생성하는 경우 [및] 1. 명령 이름에 슬래시가 포함되지 않고 [내장된 특수 유틸리티 또는 함수의 이름이 아닌 경우 ] PATH 환경 변수를 사용하여 검색해야 합니다. [찾으면 프로그램을 실행하고, 그렇지 않으면 실패합니다.]

declare간단히 말해서, 일반적인 셸 구문 분석 및 준비 논리가 아닌 단일 명령으로 수행되는 변수 참조 와 같은 작업을 수행하는 데 셸이 필요한 순서로 인해 특정 내장 명령에서만 아이디어가 작동합니다 .

모든 POSIX 셸에서 사용되는 전통적인 큰 망치 솔루션은 eval.

eval abc_$xyz=heffalump

먼저 두 단어로 구문 분석되고, 두 번째 단어는 로 확장됩니다 abc_eeyore=heffalump.그 다음에eval(단일) 인수로 전달하고 처음부터 시작하여 유효한 할당으로 구문 분석하고(현재로서는) 실행합니다 .

그러나 eval실제로모든 것abc_$xyz=heffalump이 외에도 abc_; rm -fr all_valuable_data.rm -fr /eval​자신이 하고 있는 일을 정확히 알지 않는 한 사용하는 것은 안전하지 않습니다. 알고 있다면 질문을 하지 않을 것입니다.

보다 구체적이고 안전한 솔루션은 bash에서만 가능합니다.이름 참조

suffix=eeyore
declare -n ref=abc_$suffix
ref=(1 2 3)
echo ${ref[@]} ${abc_eeyore[@]}
-> 1 2 3 1 2 3

또한 스칼라에 대한 bash에는 (원하는 배열은 아님) 다음이 있습니다.간접적인:

suffix=eeyore
ind=abc_$suffix
declare abc_$suffix=123 # or declare $ind=123
echo ${!ind}
-> 123

관련 정보