私はシェルを使用しており、zsh
私のコードには次のものがあります.zshrc
。
fpath=(~/.zsh/completion $fpath)
autoload -Uz _vc
autoload -Uz compinit
compinit
最初の行は、~/.zsh/completion
環境変数に格納されている配列にパスを追加しますfpath
。
2_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
完成が機能します。ただし、たとえば、1つがある場合、foo'bar
次のエラーメッセージで完了は失敗します。
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
(eval):56: unmatched '
行の二重引用符をcheatsheets="$(ls ~/.cheat)"
一重引用符に置き換えるソリューションを見つけましたcheatsheets='$(ls ~/.cheat)'
。
コマンドTab
の後にクリックすると、zshはインクルード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