
설명하다:
variable="Something that it holds"
그런 다음
echo "$variable"
출력됩니다: 그것이 담고 있는 내용
하지만 나도 그렇다고 가정해 보세요.
var2="variable";
echo "\$$(echo $var2)"
$variable
대신에: 무엇을 담고 있는지 만 출력합니다.
여기에서 Unix의 어떤 기능이 작동하는지 말해 줄 수 있는 사람이 있나요?
답변1
variable="Something" var2="variable"; echo "\$$(echo $var2)"
마지막 줄에서는 "\$$(echo $var2)"
→ $variable
→ 을 예상합니다 Something
. 이를 위해서는 쉘이 매개변수 확장을 두 번 수행해야 합니다. 그렇지는 않지만 단순히 $(echo $var2)
접두사가 붙은 명령 대체 결과를 인쇄합니다 $
.
원칙적으로,평가하다원하는 것을 얻을 수 있도록 도와주세요. 쉘이 첫 번째 단계 "\$$(echo $var2)"
→ 를 실행한 후 $variable
eval은 두 번째 단계 $variable
→ 를 실행합니다 Something
.
$ eval echo "\$$(echo $var2)"
Something
위 명령은 특정 사례에서는 괜찮지만 여전히 올바른 인용이 부족합니다.printf
총애를 받다echo
,
$ eval 'printf "%s\n" "${'"$var2"'}"'
Something
그러나 eval은 신뢰할 수 없는 데이터로 인해 보안 문제가 발생할 수 있습니다. 추정
var2="variable;rm importantFile"
. 이 경우 평가가 통과됩니다.
echo $variable;rm importantFile
쉘에 importantFile
추가하면 행복하게 삭제됩니다.
일부 셸(예: Bash, ksh, Zsh)에서는 다음을 사용할 수도 있습니다.간접적인. Bash의 간접 확장 구문은 다음과 같습니다.
$ echo "${!var2}"
Something
var2="variable;rm importantFile"
더 이상 문제가 아니지만 var2='a[$(rm importantFile)]'
여전히 문제입니다.
간접 참조에 대해 자세히 알아보기배쉬 매뉴얼.
매개변수의 첫 번째 문자가 느낌표(!)이고 매개변수가 nameref가 아닌 경우 간접 참조 수준이 도입됩니다. Bash는 나머지 인수를 확장하여 형성된 값을 새 인수로 사용하고 해당 값은 원래 인수의 확장이 아닌 나머지 확장에 사용됩니다.
답변2
안티 패턴(*) 냄새가 납니다. 많은 쉘에는 문자열 인덱스 배열/사전이 있습니다. in ksh93
(이 구문의 소스) bash
또는 zsh
:
typeset -A dictionary
x="keyX"
y="keyY"
dictionary[keyX]="valueX"
dictionary[$y]="valueY"
printf '%s\n' "${dictionary[$x]}"
printf '%s\n' "${dictionary[keyY]}"
(*) Linux 자체와는 아무런 관련이 없습니다. 변수에 있는 변수 이름은 매우 일반적인 변수입니다."안티패턴", 해서는 안 되는 일, 그리고 그것이 필요하다고 생각한다면 디자인에 뭔가 문제가 있는 것입니다(XY 문제)? 변수에서 변수 이름을 사용하는 대부분은 사전(존재하는 경우)으로 대체하는 것이 가장 좋습니다.
답변3
당신이 관찰하는 것은표준 행동중 하나POSIXshell: 일반적으로 말하면,
입력을 읽으십시오.
입력을 토큰(단어 및 연산자)으로 나눕니다.토큰 인식);
- 이 단계에서 다음과 같은 문제가 발생할 때마다인용되지 않음
$
(또는`
)은 확장 유형과 확장할 태그를 반복적으로 결정하여 필요한 모든 입력을 읽습니다.
- 이 단계에서 다음과 같은 문제가 발생할 때마다인용되지 않음
입력을 단순 명령과 복합 명령으로 구문 분석합니다.
다양한 수행확장하다각 명령의 다른 부분에서 (각각) 명령 및 인수로 처리되는 경로 이름 및 필드 목록을 생성합니다.
리디렉션을 수행하고 매개변수 목록에서 리디렉션 연산자와 해당 피연산자를 제거합니다.
함수, 내장 실행 파일 또는 스크립트를 실행합니다.
(선택 사항) 명령이 완료되고 종료 상태가 수집될 때까지 기다립니다.
구문 분석할 때 echo "\$$(echo $var2)"
쉘은 두 가지 확장(2단계), 즉 큰따옴표로 묶인 명령 대체 $(echo $var2)
와 따옴표가 없는 매개변수 확장을 감지합니다 $var2
. 이스케이프된 $
in은 \$
큰따옴표가 달러 \
기호 역할을 유지하므로 문자 그대로 달러 기호 로 처리됩니다.이스케이프 문자팔로우할 때 $
.
이후 단계에서는 더 이상 확장된 감지가 발생하지 않습니다. 구체적으로, 4단계( "\$$(echo $var2)"
→ "\$$(echo variable)"
→ "\$variable"
→ ) 에서 수행된 확장 결과는 $variable
확장 트리거 문자를 감지하기 위해 더 이상 구문 분석되지 않습니다.
또한 이 $
기호는 매개변수 확장의 맥락에서 변수 이름을 해당 내용으로 대체하는 데 사용되지만 범용으로 설계되지는 않았습니다.역참조 연산자.
존재하다표준 매개변수 확장, 가장 간단한 형태는 다음과 같습니다.${parameter}
, 이것parameter
사양에서는 변수 이름, 위치 매개변수 또는 특수 매개변수만 허용합니다(참조:"매개변수"의 정의). 엄밀히 말하면 매개변수 확장은 중첩될 수 없습니다. 확장 표현식은 다음과 같은 경우에만 허용됩니다.word
다양한${parameter<symbols>[word]}
형태).
다음을 사용하여 쉽게 확인할 수 있습니다.Z 쉘 제외${${foo}}
은 유효한 표현식이 아니며, 셸 $$
의 PID로 확장됩니다. 따라서 $foo
의 값으로 확장되고 foo
, $$foo
셸의 PID와 리터럴 "foo"의 연결로 확장되고, $$$foo
의 PID 연결로 확장됩니다. 쉘과 foo
, ...) 의 값 .
답변4
간접 변수 확장 외에도 bash(버전 4.3부터)에서 다음을 사용할 수도 있습니다.이름 참조
declare -n var2="variable" # "var2" is a _reference_ to "variable"
variable="Something"
echo "$var2" # => Something
variable="something else"
echo "$var2" # => something else
unset variable
echo "$var2" # => ""
이것이 어떻게 구현되는지는 모르겠지만 흥미로운 정보가 있습니다. 간접 참조를 사용하면 nameref가 참조하는 내용을 찾을 수 있습니다.
echo ${!var2} # => variable