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에서 사람들이 하는 방식으로 모듈을 만드는 데 사용할 수는 없습니다.

  • Zsh하다익명 기능이 있지만 이러한 다른 기능이 없으면 그다지 유용하지 않습니다.

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

또한 다음과 같이 정의해야 한다는 점도 지적하겠습니다 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_wherecwdchpwdgit_prompt_info

PS1각 명령 사이에 정보를 표시할 때 이를 프롬프트( 또는 배열) 의 일부로 배치하는 것이 더 나을 수 있습니다 psvar. Zsh는 다양한 상황에서 프롬프트를 다시 표시해야 한다는 것을 알고 있지만 precmd.

답변3

예, 해당 변수는 함수를 호출할 때마다 (재)정의됩니다.

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

답변4

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

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*y함수가 있습니다 (단순히 가독성을 위해 함수 이름을 선택했음을 참고하세요. 이러한 이름은 임의의 이름이 될 수 있으며 내용을 변수에 저장할 필요조차 없습니다). 또한 이들은 실제로 문자열(셸 용어의 함수가 아님)이지만 내장 기능이 있는 함수처럼 동작합니다 . 사용 예:fct_5x_plus_7y5*x+7*yeval

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

as는 2*4+3*935를 제공하고 5*4+7*983을 제공합니다.

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

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

관련 정보