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

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

zsh에는 path특수 배열 변수가 있으며 그 내용은 잘 알려진 PATH변수에 연결됩니다.

사실 함수를 정의하고 호출하는 것은 매우 특별합니다.

f() { local -r path=42 }

오류가 발생합니다 f: read-only variable: path. 지역 변수가 가변으로 선언되면(예: 없이 -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. 한숨, 다시 돌아가서 ... 좋습니다. 기본적으로 일부 매크로를 통해 기본적으로 활성화되는 것이 bin_typeset있습니다 . 대신 사용자 제공 변수가 이 코드 경로를 통해 실행되면 해당 변수 가 꺼지고 모든 것이 정상입니다.TYPESET_OPTSTRPM_READONLYPM_READONLY

읽기 전용으로 만들 수 있는 것과 같은 특수 변수를 변경할 수 있는지 여부는 pathZSH 개발자에게 질문입니다(zsh-workers 메일링 리스트를 사용해 보세요.). 그렇지 않으면 특수 변수를 다루지 마십시오.

관련 정보