zsh에서는 path
내용이 잘 알려진 변수에 연결된 특수 배열 변수입니다 PATH
.
사실 이 함수를 정의하고 호출하는 것은 매우 특별합니다.
f() { local -r path=42 }
오류가 발생합니다 f: read-only variable: path
. 지역 변수가 변경 가능하다고 선언되면(즉, not -r
) 모든 것이 예상대로 작동합니다. 다른 변수 이름을 사용하면 이 오류를 재현할 수 없습니다.
이 오류는 왜 발생합니까? 의도적인 걸까요? 다른 이름에도 비슷한 규칙이 있나요?
저는 macOS 10.12.6에서 zsh 5.2(x86_64-apple-darwin16.0)를 사용하고 있습니다.
답변1
TL;DR "특별한 내장 매개변수"를 재사용하지 마세요 path
. 또는 기반으로메일링 리스트이 -h
플래그는 다음과 같이 사용할 수 있습니다.
% () { local -hr path=42; echo $path }
42
%
(그러나 정수로 변경하면 이 재정의를 잊어버리고 ... path
라고 가정하는 후속 코드가 엉망이 될 수 있습니다 .)path
path
더 긴 발굴이 이어졌습니다(하지만 -h
숨겨진 것을 완전히 놓쳤습니다...)
% print ${(t)path}
array-special
이는 특수 변수(함수? 오류?)의 속성이지만 사용자 링크의 유사한 변수는 아닙니다.
% () { typeset -r PATH=/blah; echo $PATH }
(anon): read-only variable: PATH
% typeset -Tar FOO=bar foo
% print $foo
bar
% print ${(t)foo}
array-readonly-tag_local
% () { local -r foo=blah; echo $foo }
blah
이 동작을 나타내는 다양한 다른 매개변수가 있습니다.
% for p in $parameters[(I)*]; do print $p $parameters[$p]; done | grep array-
cdpath array-special
...
% () { local -r cdpath=42 }
(anon): read-only variable: cdpath
따라서 일부 변수는 다음과 같습니다.동물 농장남들보다 더 특별해요. 이 오류 메시지는 다양한 위치에서 발생하며, 그 중에서 Src/params.c
컴파일 타임에 찾은 메시지가 특정인지 인쇄하도록 수정하면 다음과 같습니다 zsh
.
% () { local -r path }
% () { local -r path=foo }
(anon): read-only variable (setarrvalue): path
상당히 일반적인 코드입니다
/**/
mod_export void
setarrvalue(Value v, char **val)
{
if (unset(EXECOPT))
return;
if (v->pm->node.flags & PM_READONLY) {
zerr("read-only variable (setarrvalue): %s", v->pm->node.nam);
freearray(val);
return;
}
이는 문제가 다른 곳에서 발생함을 나타냅니다. 비특수 변수는 의심할 여지 없이 PM_READONLY
설정되지 않았지만 실패한 특수 변수는 설정되었습니다. 다음으로 주목할 점은 local
다양한 이름(...)을 가진 코드 이다 typeset
export
. 이것들은 모두 내장되어 있으므로 화면에 무엇이 숨어 있는지 찾아낼 수 있습니다.Src/builtin.c
% grep BUILTIN Src/builtin.c | grep local
BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lp:%rtux", NULL),
이는 bin_typeset
다양한 플래그를 설정하는 호출이므로 함수의 소스 코드를 살펴보겠습니다. 댓글로 맹세하고 확인하세요. 상황이 복잡하므로 확인해 보세요. 토끼굴에도 불구하고("매개변수를 패턴으로 처리" -m
옵션이 선택된 경우)아니요set, 여기의 경우) 이 typeset_single
함수의 결과인 것 같습니다...
POSIXBUILTINS
관련된 코드 가 있지만 readonly
내 테스트 셸에서는 닫혀 있습니다.
% print $options[POSIXBUILTINS]
off
그래서 나는 그 코드를 무시할 것입니다. 동시에! 일부 디버깅 지점은 다음 줄을 통해 PM_READONLY
플래그가 켜져 있음을 나타냅니다.path
/*
* The remaining on/off flags should be harmless to use,
* because we've checked for unpleasant surprises above.
*/
pm->node.flags = (PM_TYPE(pm->node.flags) | on | PM_SPECIAL) & ~off;
이것은 on
함수를 입력할 때 이미 열려 있는 변수 에서 나온 것입니다. 한숨, 시작했던 곳 typeset_single
으로 돌아갑니다 ... 음, 기본적으로 사용자가 다음을 통해 변수를 제공할 때 대신 일부 매크로를 통해 기본적으로 활성화되는 변수가 있습니다. this 코드 경로가 실행되면 변수가 꺼지고 모든 것이 잘 작동합니다.bin_typeset
TYPESET_OPTSTR
PM_READONLY
PM_READONLY
path
예를 들어 특수 변수가 읽기 전용이 될 수 있도록(zsh-workers 메일링 리스트를 사용해 보세요), 그렇지 않으면 그 동안 특수 변수를 조작하지 않도록 이를 변경할 수 있는지 여부는 ZSH 개발자에게 질문입니다.