저는 Bash에서 Zsh로 천천히 마이그레이션하고 있으며 한 가지 예외를 제외하고 제가 경험한 모든 것이 잘 작동하는 지점에 도달했습니다.
.bashrc
내 프로그램에는 하루에 수십 번씩 사용하는 여러 기능이 있는데 그 중 두 개는 Zsh에서 작동하지 않습니다. 이 세 가지 기능은 기본적인 메모 기능을 구성합니다.
현재 위치는 다음과 같습니다 .config/zsh/functions
.
function n() {
local arg files=(); for arg; do files+=( ~/".notes/$arg" ); done
${EDITOR:-vi} "${files[@]}"
}
function nls() {
tree -CR --noreport $HOME/.notes | awk '{
if (NF==1) print $1;
else if (NF==2) print $2;
else if (NF==3) printf " %s\n", $3
}'
}
# TAB completion for notes
function _notes() {
local files=($HOME/.notes/**/"$2"*)
[[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]##~/.notes/}" )
}
complete -o default -F _notes n
내 출처는 .zshrc
다음과 같습니다.
autoload bashcompinit
bashcompinit
# source zshrc functions file
source "$HOME/.config/zsh/functions"
nls
예상대로 작동하지만 작업을 완료하지도 완료 n
하지도 않습니다 .Tab
나는 man zshcompsys
그것을 읽었다:
bashcompinit 함수는 bash 프로그래밍 가능 완성 시스템과의 호환성을 제공합니다. 실행되면 동일한 이름의 bash 내장 함수에 해당하는 compgen 및 Complete 함수를 정의합니다. 그런 다음 bash용으로 작성된 완성 사양 및 기능을 사용할 수 있습니다.
그러나 완료하려고 하면 Tab아무 일도 일어나지 않고 n notename
Vim은 /home
내가 입력하는 동안 파일 브라우저 모드에서 내 파일을 엽니다. 이는 정확히 예상된 동작이 아닙니다.
다른 모든 정의된 함수는 정상적으로 작동합니다. Zsh에서 작동하도록 이러한 기능을 마이그레이션하는 방법은 무엇입니까?
답변1
local
키워드가 아닌 내장 함수이므로local files=(…)
배열 할당으로 구문 분석하지 않고 문자열 할당으로 구문 분석합니다. 할당과 선언을 별도로 작성합니다. (이미llua님이 발견했습니다.files
하지만 빈 배열로 초기화하거나 선언된 변수를 사용해야 합니다typeset -a
. 그렇지 않으면 배열이 허위 빈 요소로 시작됩니다. )- Zsh 배열은 bash 및 ksh에서처럼 0이 아닌 1부터 시작하여 번호가 지정되므로
${files[0]}
로 작성해야 합니다 . 또는 함수 시작 부분$files[1]
에서 zsh에게 ksh 및 bash와 더 호환되는 방식으로 작동하도록 지시하십시오 .emulate -L ksh
emulate
이 경로를 따르지 않는 한_notes
기본적으로 일치하지 않는 glob이 오류를 트리거하기 때문에 함수가 완료되지 않으면 인쇄됩니다. 다음에 추가zsh: no matches found: foo*
foo
글로벌 예선N
일치하는 항목이 없으면 빈 배열을 가져오고 배열이 비어 있는지 테스트합니다.- 함수에는 하위 디렉토리의 주석에 영향을 미치는 또 다른 버그가 있습니다 . 예를 들어 존재하고 를 입력하면 대신 contain 로 설정
_notes
되도록 완료될 때까지 접두사를 제거해야 합니다 .~/notes/foo/bar
n b<TAB>
COMPREPLY
b
foo/b
bash와 zsh 모두에서 파일을 읽을 수 있도록 유지하려면 다음을 수행하십시오.
type emulate >/dev/null 2>/dev/null || alias emulate=true
function n() {
emulate -L ksh
local arg; typeset -a files
for arg; do files+=( ~/".notes/$arg" ); done
${EDITOR:-vi} "${files[@]}"
}
function nls() {
tree -CR --noreport $HOME/.notes | awk '{
if (NF==1) print $1;
else if (NF==2) print $2;
else if (NF==3) printf " %s\n", $3
}'
}
# TAB completion for notes
function _notes() {
emulate -L ksh
local x files
files=($HOME/.notes/**/"$2"*)
[[ -e ${files[0]} ]] || return 1
COMPREPLY=()
for x in "${files[@]}"; do
COMPREPLY+=("$2${x#$HOME/.notes*/$2}")
done
}
complete -o default -F _notes n
코드를 zsh로 포팅하려면 다음을 수행하세요.
function n() {
local files
files=(${@/#/~/.notes/})
${EDITOR:-vi} $files
}
function nls() {
tree -CR --noreport $HOME/.notes | awk '{
if (NF==1) print $1;
else if (NF==2) print $2;
else if (NF==3) printf " %s\n", $3
}'
}
# TAB completion for notes
function _notes() {
setopt local_options bare_glob_qual
local files
files=(~/.notes/**/$2*(N))
((#files)) && COMPREPLY=($2${^files##~/.notes*/$2})
}
complete -o default -F _notes n
답변2
zsh의 typeset(local) 명령은 해당 구문을 사용하여 배열을 정의할 수 없습니다. 배열을 생성할 수 있지만 하나의 명령으로 모든 값을 동시에 설정할 수는 없습니다.
function n() {
local arg files; for arg; do files+=( ~/.notes/$arg ); done
vim ${files[@]}
}
고치는 방법 중 하나입니다.