
저는 zsh
쉘을 사용하고 있으며 내부에 다음 코드가 있습니다 .zshrc
.
fpath=(~/.zsh/completion $fpath)
autoload -Uz _vc
autoload -Uz compinit
compinit
~/.zsh/completion
첫 번째 줄은 환경 변수 내에 저장된 배열에 경로를 추가합니다 fpath
.
_vc
두 번째 줄은 이라는 사용자 정의 셸 함수에 대한 이라는 완성 함수를 로드합니다 vc
. 의 목적은 vc
단순히 특정 폴더( ~/.cheat
) 내의 파일을 편집하는 것입니다. _vc
파일에 정의되어 있습니다 ~/.zsh/completion/_vc
.
마지막 2줄은 완성 시스템을 활성화합니다.
내 완성 기능에 대한 코드는 다음과 같습니다 _vc
.
#compdef vc
declare -a cheatsheets
cheatsheets="$(ls ~/.cheat)"
_arguments "1:cheatsheets:(${cheatsheets})" && return 0
이것부터 복사했어요주소, 내 필요에 맞게 조정했습니다.
디렉터리에 ~/.cheat
이름에 작은따옴표가 포함된 파일이 없으면 완성이 작동합니다. 그러나 와 같은 것이 있는 경우 foo'bar
다음 오류 메시지와 함께 완료가 실패합니다.
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
줄의 큰따옴표를 cheatsheets="$(ls ~/.cheat)"
작은따옴표로 바꾸는 방법으로 해결책을 찾았습니다 cheatsheets='$(ls ~/.cheat)'
.
이제 명령을 실행하면 Tab
zsh 는 (zsh가 작은따옴표를 자동으로 이스케이프 처리한 것 같습니다)를 포함하여 vc
내부 파일을 제안합니다 .~/.cheat
foo\'bar
그러나 나는 그것이 어떻게, 왜 작동하는지 이해하지 못합니다. 작은따옴표를 사용하면 변수 cheatsheets
sould에 리터럴 문자열이 포함됩니다. 따라서 $(...)
명령 대체를 확장해서는 안 됩니다. 예를 들어, 다음 명령을 실행하면:
myvar='$(ls)'
echo $myvar → outputs `$(ls)` literally
그렇다면 왜 '$(ls ~/.cheat)'
내부가 확장 됩니까 _arguments "1:cheatsheets:(${cheatsheets})" && return 0
? 그리고 내부의 작은따옴표를 자동으로 이스케이프 처리하는 이유는 무엇입니까 foo'bar
?
답변1
우리가 일을 고집한다면 The Wrong Way™
#compdef vc
declare -a cheatsheets
cheatsheets=(${(f)"$(ls ~/.cheat/)"})
_arguments '1:cheatsheets:(${cheatsheets})' && return 0
왝! 물론 이것은 파일 이름에 개행 문자가 포함되어 있으면 중단됩니다 (f)
.파싱은 ls
어쨌든 나쁜 생각이다; ZSH는 파일을 배열에 직접 glob할 수 있습니다.
% mkdir ~/.lojban
% touch ~/.lojban/{go\'i,na\ go\'i}
% words=(~/.lojban/*)
% print -l ${words:t}
go'i
na go'i
% words=(~/.lojban/*(On))
% print -l ${words:t}
na go'i
go'i
%
하지만 아마도 로컬 배열은 필요하지 않을 것입니다. _files
glob에서 완료할 수 있습니다.
#compdef vc
_arguments '1:cheatsheets:_files -g "~/.cheat/*"' && return 0
이는 정규화된 파일 경로를 반환합니다. 검색 디렉터리에서 기본 파일 이름만 필요한 경우 대신 다음을 사용할 수 있습니다.
#compdef vc
_arguments '1:cheatsheets:_files -W ~/.cheat' && return 0