zsh에 클로저와 같은 것이 있습니까?

zsh에 클로저와 같은 것이 있습니까?

방금 oh-my-zsh를 통해 zsh를 시도하기로 결정했고 이제 precmd마지막 줄에 올바른 프롬프트가 없는 두 줄 프롬프트를 에뮬레이션하려고 합니다.

그래서 기본 테마를 복제하고 영감을 얻었습니다.이 게시물(나는 또한 많은 것을 배우기 위해 그것을 사용합니다), 나는 다음과 같이 했습니다(나중에 색상을 추가할 것입니다):

function precmd {
    local cwd="${(%):-[%~]}"
    local who_where="${(%):-%n@%m}"
    local git_info=${(%)$(git_prompt_info)}
    local right_prompt="     $git_info [$who_where]"
    local left_prompt="${(r:(($COLUMNS - ${#${right_prompt}})):: :)cwd}"

    echo "$left_prompt$right_prompt"
}

효과가있다. 하지만 궁금하지 않을 수 없습니다. precmd가 호출될 때마다 zsh가 이러한 모든 변수를 정의합니까?

나는 zsh와 관련된 클로저, 범위 및 네임 스페이스에 대해 인터넷 검색을 해왔고 변수를 매번 재정의 할 필요가 없도록 지역 변수를 precmd에 데이터로 추가하기를 희망했지만 아무것도 찾지 못했습니다. 내가 하고 있는 일을 할 수 있는 방법이 있나요, 아니면 포기해야 하나요?

참고로 관련성이 있는 경우에만 "함수 로드"란 무엇을 의미합니까?

답변1

Zsh에는 클로저, 패키지 또는 네임스페이스와 같은 것이 없습니다. Zsh에는 실제 클로저를 구현하는 데 필요한 내용이 누락되어 있습니다.

  • 기능은 최고 수준이 아닙니다. 함수를 다른 함수에 인수로 전달할 수 없으며 함수는 다른 함수를 반환할 수 없습니다. (이 작업은 다음을 통해 수행할 수 있습니다.이름호출할 함수의 이름이지만 함수 자체를 전달하는 것과는 다릅니다.

  • 중첩된 함수는 있을 수 없습니다. zsh의 모든 기능은 전역적입니다. 충돌을 방지하려면 함수 이름 앞에 접두사를 붙여야 합니다. 특히 이 기능은 동일한 이름을 가진 외부 프로그램을 숨긴다는 점에 유의하세요. 라는 함수가 있으면 ls프로그램 대신 해당 함수가 호출됩니다 ls. 실수로 하지 않는 한 이는 유용할 수 있습니다.

  • 변수의 범위는 대부분의 현대 언어처럼 정적이 아니라 동적입니다. 중첩된 함수가 있을 수 있더라도 내부 함수는 일반적으로 예상하는 방식으로 외부 함수의 지역 변수를 닫지 않습니다. 사람들이 Javascript를 사용하는 것처럼 모듈을 만드는 데 사용할 수는 없습니다.

  • 지쉬하다익명 함수도 있지만, 다른 것이 없으면 별로 쓸모가 없습니다.

따라서 기본적으로 가장 좋은 방법은 모든 함수와 전역 변수에 접두사를 붙이는 것입니다.

precmd또한 다음과 같이 정의 해야 한다는 점을 지적하고 싶습니다 .

% autoload -Uz add-zsh-hook
% add-zsh-hook precmd my_precmd_function

add-zsh-hookprecmd연결하려는 다른 함수를 재정의하지 않고 함수를 연결할 수 있습니다 precmd.

함수 로딩이 무엇을 의미하는지는 별도의 질문입니다. Zsh에는 실제로 호출될 때만 디스크에서 함수를 로드하는 자동 로딩 기능이 있습니다. 이렇게 하면 autoload -Uz foobar이름이 지정된 함수를 호출할 수 있습니다. foobar실제로 호출하면 foobar정의가 디스크에서 로드됩니다.

답변2

아니요, 클로저는 zsh에 비해 너무 복잡합니다. Zsh는 직접적인 상호 작용에서 크게 벗어나지 않는 작은 스크립트를 해석하도록 설계되었습니다. 대규모 프로그래밍에 유용한 멋진 언어 기능은 없지만 일반적으로 쉘을 사용하여 수행하는 작은 작업에는 덜 유용합니다.

변수 값을 미리 계산한 다음 완전히 저장할 수 있는 클로저 형식이 있는 경우 일부 변경으로 인해 정보가 유효하지 않게 될 때 해당 값은 업데이트되지 않습니다.

$git_info파생 변수는 git 또는 git 저장소에 체크인된 파일 수정으로 인해 언제든지 변경될 수 있습니다. 따라서 어쨌든 매번 다시 계산해야 합니다.

cwd전역 변수 의 값은 who_where일반 작업에서는 변경되지 않으므로 캐시할 수 있습니다. cwd현재 디렉토리가 변경되면 현재 디렉토리도 변경되므로 에서 변경해야 합니다 chpwd. 그러나 이러한 변수는 매우 빠르게 계산되므로 귀찮게 할 필요가 없습니다. 여기에서는 값비싼 계산이 실행되고 git_prompt_info있으며 언제든지 변경될 수 있습니다.

PS1각 명령 사이에 정보를 표시할 때는 프롬프트( 또는 배열) 의 일부로 수행하는 것이 가장 좋습니다 psvar. Zsh는 다양한 상황에서 프롬프트를 다시 표시해야 한다는 것을 알고 있지만 인쇄한 내용에 대해서는 아무것도 모릅니다 precmd.

답변3

예, 이러한 변수는 함수가 호출될 때마다 (재)정의됩니다.

한 번만 초기화하려는 경우 함수의 최상위 수준으로 간단히 이동할 수 있습니다.

답변4

클로저를 구현하려면 언어가 함수를 요소나 객체로 작동할 수 있어야 하는데, 이는 문자열과 내장 함수 eval(다른 쉘에서와 같이)를 통하지 않고는 zsh에서는 불가능합니다. 그러나 참조와 같은 모든 하위 수준 항목을 직접 처리해야 하므로 이는 매우 제한적입니다. 그러나 인수에 특수 문자가 없는 경우(따라서 참조를 처리할 필요가 없는 경우) 이 아이디어를 사용하여 간단한 작업을 수행하는 것은 쉽고 zsh에서는 익명 함수가 약간 도움이 될 수 있습니다. 예를 들어, a*x+b*y와 는 함수 정의 시 제공되는 상수 a이고 함수에 대한 인수인 계산된 함수를 정의하려면 다음 을 수행합니다.bxy

mk_ax_plus_by() { echo "() { echo \$((($1)*(\$1)+($2)*(\$2))) }" }

fct_2x_plus_3y=$(mk_ax_plus_by 2 3)
fct_5x_plus_7y=$(mk_ax_plus_by 5 7)

fct_2x_plus_3y따라서 계산 함수 2*x+3*yfct_5x_plus_7y계산 함수가 있습니다 5*x+7*y(단지 가독성을 위해 함수 이름을 선택했다는 점에 유의하세요. 이러한 이름은 무엇이든 가능하며 내용을 변수에 저장할 필요도 없습니다). 또한 이들은 실제로 문자열(쉘 용어로 함수가 아님)이지만 eval내장 함수처럼 동작합니다. 사용 예:

% eval $fct_2x_plus_3y 4 9
35
% eval $fct_5x_plus_7y 4 9
83

2*4+3*935를 주고 5*4+7*983을 줍니다.

함수형 언어와 달리 여기서는 환경에서 오는 매개변수(따옴표 없음)와 함수를 정의하는 매개변수(따옴표 있음)를 구별해야 합니다. 즉, 함수가 호출될 때만 평가됩니다. 그러나 구현을 기능적 언어와 비슷하게 변경할 수 있으며 사용법은 동일합니다.

mk_ax_plus_by()
{
  local x='$1' y='$2'
  echo "() { echo \$((($1)*($x)+($2)*($y))) }"
}

관련 정보