zsh에서 path라는 읽기 전용 변수를 정의할 수 없는 이유는 무엇입니까?

zsh에서 path라는 읽기 전용 변수를 정의할 수 없는 이유는 무엇입니까?

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라고 가정하는 후속 코드가 엉망이 될 수 있습니다 .)pathpath

더 긴 발굴이 이어졌습니다(하지만 -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_typesetTYPESET_OPTSTRPM_READONLYPM_READONLY

path예를 들어 특수 변수가 읽기 전용이 될 수 있도록(zsh-workers 메일링 리스트를 사용해 보세요), 그렇지 않으면 그 동안 특수 변수를 조작하지 않도록 이를 변경할 수 있는지 여부는 ZSH 개발자에게 질문입니다.

관련 정보