나는 zsh
쉘을 사용하고 있으며 내 코드에는 다음이 있습니다 .zshrc
.
fpath=(~/.zsh/completion $fpath)
autoload -Uz _vc
autoload -Uz compinit
compinit
첫 번째 줄은 ~/.zsh/completion
환경 변수에 저장된 배열에 경로를 추가합니다 fpath
.
두 번째 _vc
줄은 이름이 지정된 사용자 정의 셸 함수에 대해 이름이 지정된 완성 함수를 로드합니다 vc
. vc
특정 폴더( ) ~/.cheat
내의 파일을 편집하는 용도로만 사용 됩니다. _vc
파일에 정의되어 있습니다 ~/.zsh/completion/_vc
.
마지막 두 줄은 완성 시스템을 활성화합니다.
완성된 함수에 대한 코드는 다음과 같습니다 _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가 include vc
내의 파일을 제안합니다 (zsh가 자동으로 작은따옴표를 이스케이프 처리한 것 같습니다).~/.cheat
foo\'bar
그러나 나는 그것이 어떻게, 왜 작동하는지 이해하지 못합니다. 작은따옴표를 사용하는 경우 변수에는 cheatsheets
리터럴 문자열이 포함되어야 합니다. 따라서 $(...)
명령 대체를 확장해서는 안 됩니다. 예를 들어, 다음 명령을 실행하면:
myvar='$(ls)'
echo $myvar → outputs `$(ls)` literally
그렇다면 왜 '$(ls ~/.cheat)'
확장해야 할까요 _arguments "1:cheatsheets:(${cheatsheets})" && return 0
? 내부의 작은따옴표를 자동으로 이스케이프 처리하는 이유는 무엇입니까 foo'bar
?
답변1
우리가 일을 잘못된 방식으로 고집한다면™
#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