
zsh에서 자체 쉘 기능을 정의하고 실행하는 데 문제가 있습니다. 나는 팔로우한다설명하다공식 문서에서 먼저 간단한 예제를 사용해 보았지만 제대로 작동하지 못했습니다.
폴더가 있습니다.
~/.my_zsh_functions
functions_1
이 폴더에는 "With User Permissions"라는 파일이 있습니다 rwx
. 이 파일에서는 다음과 같은 쉘 함수를 정의합니다.
my_function () {
echo "Hello world";
}
FPATH
포함 폴더의 경로를 정의했습니다 ~/.my_zsh_functions
.
export FPATH=~/.my_zsh_functions:$FPATH
다음을 사용하여 폴더가 .my_zsh_functions
함수 경로에 있는지 확인할 수 있습니다.echo $FPATH
echo $fpath
그러나 쉘에서 다음을 시도하면:
> autoload my_function
> my_function
나는 얻다:
zsh: my_test_function: 함수 정의 파일을 찾을 수 없습니다.
전화를 걸려면 다른 조치를 취해야 합니까 my_function
?
고쳐 쓰다:
지금까지의 대답은 zsh 기능을 사용하여 파일을 얻는 것을 제안합니다. 이것은 말이 되지만 조금 혼란스럽습니다. zsh는 이러한 파일이 어디에 있는지 알아야 하지 않습니까 FPATH
? 목적은 무엇입니까 autoload
?
답변1
zsh에서 함수 검색 경로($fpath)는 포함된 함수가 처음 필요할 때 자동 로딩으로 표시할 수 있는 파일이 포함된 디렉터리 집합을 정의합니다.
Zsh에는 파일을 자동으로 로드하는 두 가지 모드가 있습니다. Zsh의 기본 방식과 ksh의 자동 로딩과 유사한 또 다른 모드입니다. KSH_AUTOLOAD 옵션이 설정된 경우 후자가 활성화됩니다. Zsh의 기본 모드가 기본값이므로 여기서는 대안에 대해 논의하지 않겠습니다(ksh 스타일 자동 로딩에 대한 자세한 내용은 "man zshmisc" 및 "man zshoptions" 참조).
좋아요 "~/.zfunc" 디렉토리가 있고 이를 함수 검색 경로의 일부로 사용하려는 경우 다음을 수행할 수 있습니다.
fpath=( ~/.zfunc "${fpath[@]}" )
그러면 개인 디렉터리가 다음에 추가됩니다.앞쪽검색 경로. 이는 zsh 설치의 기능을 자체 설치로 대체하려는 경우 중요합니다(예: 이전 설치의 쉘 버전이 있는 zsh CVS 저장소의 "_git"과 같은 최신 완성 항목을 사용하려는 경우).
"$fpath"의 디렉터리는 재귀적으로 검색되지 않는다는 점도 주목할 가치가 있습니다. 개인 디렉터리를 재귀적으로 검색하려면 아래와 같이 이를 직접 처리해야 합니다(다음 코드 조각에서는 "EXTENDED_GLOB" 옵션을 설정해야 함).
fpath=(
~/.zfuncs
~/.zfuncs/**/*~*/(CVS)#(/N)
"${fpath[@]}"
)
훈련받지 않은 사람의 눈에는 비밀스러워 보일 수도 있지만 실제로는 "CVS"라는 이름의 디렉터리를 무시하면서 `~/.zfunc' 아래의 모든 디렉터리를 `$fpath'에 추가합니다(전체 디렉터리를 확인하려는 경우 유용합니다). zsh의 CVS에서 개인 검색 경로에 함수 트리를 추가하려면).
다음 줄을 포함하는 "~/.zfunc/hello" 파일이 있다고 가정합니다.
printf 'Hello world.\n'
지금 당신이 해야 할 일은표시처음 참조할 때 자동으로 로드되는 함수:
autoload -Uz hello
"-Uz가 무슨 뜻인가요?"라고 물을 수도 있습니다. 어떤 옵션이 설정되어 있든 자동 로드가 올바른 작업을 수행하도록 하는 옵션 집합일 뿐입니다. "U"는 함수를 로드할 때 별칭 확장을 비활성화하고, "z"는 어떤 이유로 "KSH_AUTOLOAD"가 설정된 경우에도 zsh 스타일 자동 로드를 강제합니다.
처리 후 새로운 "hello" 기능을 사용할 수 있습니다.
zsh% 안녕하세요 안녕하세요 월드.
이 파일을 얻는 방법에 대해 한마디:잘못된. "~/.zfunc/hello" 파일을 얻으면 "Hello world"만 인쇄됩니다. 한 번. 그게 다야. 어떤 기능도 정의되지 않습니다. 또한 코드가 호출될 때만 함수를 로드하는 것이 아이디어입니다.필수의. "autoload" 호출 후 함수 정의는 다음과 같습니다.아니요읽다. 이 기능은 필요에 따라 나중에 자동으로 로드되도록 간단히 표시됩니다.
마지막으로 $FPATH 및 $fpath에 대한 참고 사항: Zsh는 이를 링크 매개변수로 유지합니다. 소문자 인수는 배열입니다. 대문자 버전은 항목을 연결하는 콜론과 함께 연결된 배열의 항목을 포함하는 문자열 스칼라입니다. 이는 배열을 사용하여 스칼라 목록을 처리하는 동시에 스칼라 매개변수를 사용하는 코드에 대해 이전 버전과의 호환성을 유지하는 것이 더 자연스럽기 때문입니다. $FPATH(스칼라)를 사용하기로 선택한 경우 다음 사항에 주의해야 합니다.
FPATH=~/.zfunc:$FPATH
작동하지만 다음은 작동하지 않습니다.
FPATH="~/.zfunc:$FPATH"
그 이유는 큰따옴표 내에서는 물결표 확장이 수행되지 않기 때문입니다. 이것이 문제의 원인일 수 있습니다. echo $FPATH
확장된 경로 대신 물결표를 인쇄 하면 작동하지 않습니다. 안전을 위해 다음과 같이 물결표 대신 $HOME을 사용합니다.
FPATH="$HOME/.zfunc:$FPATH"
즉, 나는 이 설명의 맨 위에서 했던 것처럼 배열 매개변수를 사용하는 것을 선호합니다.
또한 $FPATH 매개변수를 내보내면 안 됩니다. 이는 하위 프로세스가 아닌 현재 쉘 프로세스에만 필요합니다.
고쳐 쓰다
"$fpath"의 파일 내용에 관해:
zsh 스타일 자동 로딩의 경우 파일 내용은 파일이 정의하는 함수의 본문입니다. 따라서 "hello"라는 파일에는 echo "Hello world."
"hello"라는 함수를 완전히 정의하는 줄이 포함되어 있습니다. hello () { ... }
원하는 대로 코드를 수정할 수 있지만 이는 중복됩니다.
그러나 파일에 하나의 기능만 포함될 수 있다는 것은 전적으로 사실이 아닙니다.
특히 함수 기반 완성 시스템(compsys)의 일부 기능을 살펴보면 이것이 오해라는 것을 금방 깨닫게 될 것이다. 함수 파일에서 추가 함수를 자유롭게 정의할 수 있습니다. 또한 함수를 처음 호출할 때 필요한 모든 종류의 초기화를 자유롭게 수행할 수도 있습니다. 그런데 이렇게 하면 항상 파일에 파일과 같은 이름으로 함수를 정의하게 되고,이 함수를 호출하세요파일 끝에 있으므로 함수가 처음 참조될 때 실행됩니다.
하위 함수에 대해 파일에 있는 것과 유사한 함수를 정의하지 않으면 함수 정의(즉, 파일에 있는 하위 함수에 대한 함수 정의)를 포함하는 함수 내의 함수로 끝납니다. 파일과 같은 이름의 함수를 호출할 때마다 모든 하위 함수를 효과적으로 정의하게 됩니다. 일반적으로 그것은아니요무엇을 원하니 파일에 있는 파일과 비슷한 이름으로 함수를 다시 정의해야 합니다.
작동 방식에 대한 아이디어를 제공하기 위해 간단한 프레임워크를 제공하겠습니다.
# Let's again assume that these are the contents of a file called "hello".
# You may run arbitrary code in here, that will run the first time the
# function is referenced. Commonly, that is initialisation code. For example
# the `_tmux' completion function does exactly that.
echo initialising...
# You may also define additional functions in here. Note, that these
# functions are visible in global scope, so it is paramount to take
# care when you're naming these so you do not shadow existing commands or
# redefine existing functions.
hello_helper_one () {
printf 'Hello'
}
hello_helper_two () {
printf 'world.'
}
# Now you should redefine the "hello" function (which currently contains
# all the code from the file) to something that covers its actual
# functionality. After that, the two helper functions along with the core
# function will be defined and visible in global scope.
hello () {
printf '%s %s\n' "$(hello_helper_one)" "$(hello_helper_two)"
}
# Finally run the redefined function with the same arguments as the current
# run. If this is left out, the functionality implemented by the newly
# defined "hello" function is not executed upon its first call. So:
hello "$@"
이 어리석은 예제를 실행하면 첫 번째 실행은 다음과 같습니다.
zsh% 안녕하세요 초기화 중... 안녕하세요 월드.
연속 호출은 다음과 같습니다.
zsh% 안녕하세요 안녕하세요 월드.
문제가 해결되기를 바랍니다.
(이러한 모든 기술을 사용하는 보다 복잡한 실제 사례 중 하나는 이미 언급한 `_tmux' zsh의 함수 기반 완성 시스템의 함수입니다. )
답변2
요소에 의해 명명된 디렉터리의 파일 이름은 fpath
해당 요소가 정의하는 자동 로드 기능의 이름과 일치해야 합니다.
함수의 이름이 지정 my_function
되고 ~/.my_zsh_functions
예상 디렉터리에 있으므로 fpath
정의는 my_function
해당 파일에 있어야 합니다 ~/.my_zsh_functions/my_function
.
제안된 파일 이름의 복수형( )은 functions_1
파일에 여러 기능을 배치할 계획임을 나타냅니다. 이는 자동 로딩이 작동하는 방식이 아닙니다 fpath
. 각 파일에는 함수 정의가 있어야 합니다.
답변3
당신이 원하는 것은 초기화가 지연되는 기능이기 때문에 구매는 확실히 올바른 접근 방식이 아닙니다. 그것이 autoload
목적입니다. 목표를 달성하는 방법은 다음과 같습니다.
당신은 echo "hello world"라는 함수를 ~/.my_zsh_functions
넣고 싶다고 말했습니다 my_function
. 그러나 함수 호출로 래핑하는데 이는 작동 방식이 아닙니다. ~/.my_zsh_functions/my_function
대신에 echo "Hello world"
함수 래퍼가 아닌 이라는 함수를 만들어야 합니다 . 포장지를 정말 선호한다면 그렇게 할 수도 있습니다.
# ~/.my_zsh_functions/my_function
__my_function () {
echo "Hello world";
}
# you have to call __my_function
# if this is how you choose to do it
__my_function
다음으로 파일 .zshrc
에 다음을 추가합니다 .
fpath=(~/.my_zsh_functions $fpath);
autoload -U ~/.my_zsh_functions/my_function
새 ZSH 셸을 로드할 때 를 입력합니다 which my_function
. 다음이 표시되어야 합니다.
my_function () {
# undefined
builtin autoload -XU
}
ZSH가 방금 my_function을 제거했습니다 autoload -X
. 이제 my_function
를 입력하고 실행하세요 my_function
. 인쇄물이 표시되어야 하며 Hello world
이제 실행하면 which my_function
다음과 같이 함수가 채워지는 것을 볼 수 있습니다.
my_function () {
echo "Hello world"
}
이제 전체 ~/.my_zsh_functions
폴더 가 autoload
..zshrc
# add ~/.my_zsh_functions to fpath, and then lazy autoload
# every file in there as a function
fpath=(~/.my_zsh_functions $fpath);
autoload -U $fpath[1]/*(.:t)
답변4
다음과 같이 $ZDOTDIR/.zshrc의 모든 기능이 포함된 파일을 "로드"할 수 있습니다.
source $ZDOTDIR/functions_file
또는 "source" 대신 점 "."을 사용할 수 있습니다.