일부 코드를 작성하는 동안 다음 줄을 발견했습니다.
$ TZ="America/Los_Angeles" date; echo "$TZ"
Thu Dec 24 14:39:15 PST 2015
"로스앤젤레스"의 실제 시간을 올바르게 제공하고 TZ
변수 값을 유지하지 않습니다. 모든 것이 예상대로 작동합니다.
그러나 이 줄에서는 일부 서식을 확장하고 본질적으로 동일한 작업을 수행하여 TZ 값을 유지하는 데 사용합니다.
TZ="America/Los_Angeles" eval date; echo "$TZ"
Thu Dec 24 14:41:34 PST 2015
America/Los_Angeles
많은 테스트 후에 이것이 특정 쉘에서만 발생한다는 것을 발견했습니다. dash, ksh에서는 발생하지만 bash 또는 zsh에서는 발생하지 않습니다.
질문됨
문제는 다음과 같습니다
- 현재 쉘에 TZ 값이 유지되는 이유는 무엇입니까?
- (가능한 경우) 이를 어떻게 피하거나 제어할 수 있습니까?
추가의.
다음 두 줄을 사용하여 여러 셸에서 테스트를 실행했습니다.
myTZ="America/Los_Angeles"
unset TZ; { TZ="$myTZ" date; } >/dev/null; echo -n " direct $TZ"
unset TZ; { TZ="$myTZ" eval date; } >/dev/null; echo " evaled $TZ"
결과 :
/bin/ash : direct evaled America/Los_Angeles
/bin/dash : direct evaled America/Los_Angeles
/bin/sh : direct evaled America/Los_Angeles
/bin/bash : direct evaled
/bin/ksh93 : direct evaled America/Los_Angeles
/bin/lksh : direct evaled America/Los_Angeles
/bin/mksh : direct evaled America/Los_Angeles
/bin/zsh : direct evaled
/bin/zsh4 : direct evaled
TZ 값은 bash 및 zsh를 제외한 모든 쉘에서 실행 중인 쉘에 영향을 미칩니다.
답변1
당신이 발견했듯이 이것은 표준적인 동작입니다. 그러나 그것은 또한 의미가 있습니다.
명령줄에 정의를 추가할 때 다른 명령이 다른 환경 변수의 값을 유지하는 것과 같은 이유로 값은 셸 환경에 유지됩니다. 환경에서 변수를 설정하는 것입니다.
이것특수 내장 기능일반적으로 모든 쉘의 가장 필수적인 종류 - eval
기본적으로 쉘 파서의 액세스 가능한 이름, set
쉘 옵션 및 쉘 인수 추적 및 구성, return
// 루프 제어 흐름 트리거, break
신호 처리, 파일 열기/닫기. 이는 포장지를 거의 또는 전혀 사용하지 않고도 얻을 수 있는 기본 유틸리티입니다.continue
trap
exec
대부분의 명령을 실행하려면 일부 계층화된 환경이 필요합니다.서브쉘 환경(반드시 별도의 프로세스일 필요는 없음)- 특수 내장 함수를 호출하면 알 수 없습니다. 따라서 이러한 명령 중 하나에 대한 환경을 설정하면 셸에 대한 환경도 설정됩니다. 기본적으로 쉘을 나타내기 때문입니다.
그러나 이러한 방식으로 환경을 보존하는 명령은 이것뿐만이 아닙니다. 함수도 동일한 작업을 수행합니다. 오류는 특수 내장 명령에 대해 다르게 동작합니다. cat <doesntexist
try 이후에 시도하거나 명령이 불평할 때나 POSIX 쉘을 종료할 exec <doesntexist
때도 마찬가지입니다 . 명령줄의 확장 오류도 마찬가지입니다. 그들은: <doesntexist
cat
exec
:
메인 루프, 기본적으로.
이러한 명령은가지다환경을 보존하기 위해 일부 셸은 내부를 다른 셸보다 더 단단하게 감싸서 핵심 기능을 덜 노출하고 프로그래머와 인터페이스 사이에 더 많은 버퍼를 추가합니다. 이러한 동일한 쉘은 다른 쉘보다 느릴 수도 있습니다. 물론 규정을 준수하려면 비표준적인 조정이 많이 필요합니다. 아무튼 이건 아닌데나쁜물건:
fn(){ bad_command || return=$some_value return; }
그 것은단순한. 그렇지 않으면 bad_command
여러 가지 설정을 하지 않고 어떻게 반환 값을 그렇게 간단하게 유지할 수 있습니까?추가의환경이지만 여전히 조건부로 작업을 수행합니까?
arg=$1 shift; x=$y unset y
이 물건도 작동합니다. 제자리에서 교체하는 것이 더 간단합니다.
IFS=+ set -- "$IFS" x y z
x="$*" IFS=$1 shift
echo "${x#"$IFS"}" "$*"
+x+y+z x y z
...또는...
expand(){
PS4="$*" set -x "" "$PS4"
{ $1; } 2>&1
PS4=$2 set +x
} 2>/dev/null
x='echo kill my computer; $y'
y='haha! just kidding!' expand "${x##*[\`\(]*}"
...내가 즐겨 사용하는 또 하나는...
echo kill my computer; haha! just kidding!
답변2
이러한 행동에는 매우 구체적인 이유가 있는 것으로 밝혀졌습니다.
무슨 일이 일어났는지에 대한 설명이 좀 길었습니다.
그냥 숙제.
할당으로 구성된 명령줄(만)은 변수를 설정합니다.이것껍데기.
$ unset a b c d
$ a=b c=d
$ echo "<$a::$c>"
<b::d>
할당된 변수값은 유지됩니다.
외부 명령.
외부 명령이 변수를 설정하기 전 할당저것셸만 해당:
$ unset a b c d
$ a=b c=d bash -c 'echo "one:|$c|"'; echo "two:<$c>"
one:|d|
two:<>
"외부"란 PATH에서 검색해야 하는 모든 명령을 의미합니다.
이는 일반 내장 명령(예: cd)에서도 작동합니다.
$ unset a b c d; a=b c=d cd . ; echo "<$a::$c>"
<::>
지금까지는 모든 것이 정상적으로 예상된 대로입니다.
특수 내장.
하지만 특수 내장 기능의 경우POSIX에서는 이 셸에 대해 값을 설정해야 합니다..
- 지정된 변수에 값을 할당합니다.특수 내장 유틸리티내장이 완료된 후에도 여전히 유효합니다.
$ sh -c 'unset a b c d; a=b c=d export f=g ; echo "<$a::$c::$f>"'
<b::d::g>
POSIX 호환 쉘이라고 sh
가정하고 호출을 사용하고 있습니다 .sh
이것은 일반적으로 사용되는 것이 아닙니다.
즉, 이 특수 내장 함수 목록 앞에 오는 할당은 현재 실행 중인 셸에서 지정된 값을 유지해야 함을 의미합니다.
break : continue . eval exec exit export
readonly return set shift times trap unset
쉘이 POSIX 사양에 따라 작동하는 경우 이런 일이 발생합니다.
결론적으로:
명령이 다음과 같은지 확인하여 하나의 명령(모든 명령)에 대해 변수를 설정할 수 있습니다.아니요특별한 내장. 이 명령 command
은 일반 내장 명령입니다. 함수가 아닌 명령을 사용하도록 쉘에 지시할 뿐입니다. 이 줄은 모든 셸에서 작동합니다(ksh93 제외).
$ unset a b c d; a=b c=d command eval 'f=g'; echo "<$a::$c::$f>"
<::::g>
이 경우 변수 a와 b는 명령 환경에 대해 설정된 후 삭제됩니다.
대신 할당된 값이 유지됩니다(bash 및 zsh 제외).
$ unset a b c d; a=b c=d eval 'f=g'; echo "<$a::$c::$f>"
<b::d::g>
노트eval 이후의 할당은 불필요한 확장을 방지하기 위해 작은따옴표로 묶였습니다.
따라서 명령 환경에 변수를 넣으려면 다음을 사용하십시오 command eval
.