我有自定义脚本,需要:
- 短/长格式的可选参数
- 一个必需的命令行参数
短/长命令行选项例如:
-r, --readonly
-m, --mount
对于一个必需的参数,这些参数实际上在脚本中指定为 case 语句,即foo
在bar
此示例中:
case $1 in
foo )
:
;;
bar )
:
;;
如何zsh completion
为我的脚本创建,以便在参数以 开头时完成可选参数-
,并从我的脚本 case 语句中获取所需参数?
更新:
这是我到目前为止所得到的,受到答案的启发@Marlon Richert
。
假设调用我的自定义脚本myscript.sh
并且我创建的完成规则位于/usr/share/zsh/functions/Completion/Unix/_myscript.sh
:
#compdef myscript.sh
_myscript () {
local -a args
args+=(
{-r,--readonly}'[description for "readonly"]'
{-m,--mount}'[description for "mount"]'
)
_arguments $args && return
}
_myscript "$@"
我的脚本myscript.sh
本身位于/usr/local/bin/myscript.sh
.
因此,现在当我有了可选参数-r
并-m
得到处理时,我需要修改我的完成规则,以便对于我的脚本所需的命令行参数,来自 case 语句的项目/usr/local/bin/myscript.sh
作为完成提供。
另外,我不确定args+=(
完成脚本中第 6 行开始的块的语法是否正确。我必须在哪里放置单引号?
答案1
假设您要为其定义完成的函数称为myfunc
。
首先,让我们设置实际的功能:
- 将您的函数放在名为
myfunc
.笔记:- 这不会以
.zsh
或结尾.sh
。 - 当您将函数放入其自己的文件中时,无需添加
funcname() {…}
样板文件。
- 这不会以
- 确保包含该文件的目录
myfunc
位于您的$fpath
.例如,如果文件myfunc
位于~/Functions
,请将其添加到您的~/.zshrc
文件中:fpath+=( ~/Functions )
- 最后,自动加载
myfunc
到您的文件中~/.zshrc
:# We pass a couple of options that make the code # less likely to break: # -U suppresses alias expansion # -z marks the function for zsh-style autoloading == # `unsetopt KSH_AUTOLOAD` autoload -Uz myfunc
您现在应该能够myfunc
在命令行上使用(但还没有任何完成)。
接下来,让我们创建完成函数:
- 创建一个名为
_myfunc
. - 放入此文件中:
#compdef myfunc # The line above means "This function generates # completions for myfunc." # The combination of that line, plus the file name # starting with an `_`, plus having this file's # parent dir in your `$fpath`, ensures this file # will be autoloaded when you call `compinit`. # `+X` makes sure `myfunc`'s definition will get # loaded immediately, even if you have not called # this function yet. autoload +X -Uz myfunc # Get the definition of `myfunc` in string form. local funcdef="$( type -f myfunc )" # Get the part that matches `case*esac`, then split # it on whitespace and put the resulting words in an # array. local -a words=( ${=funcdef[(r)case,(r)esac]} ) # Keep only the words that start with `(` and end # with `)`. # Even if you used the `case` syntax with only the # closing `)`s, `type -f` will show your cases with # both `(` and `)`. local -a required=( ${(M)words:#'('*')'} ) # `-s`: Allow options to `myfunc ` to be stacked, # that is, you are allowed to specify `myfunc -rm`. # If not, remove the `-s` option. # `*:`: Let this argument be completed in any # position. _arguments -s \ {-r,--readonly}'[description for "readonly"]' \ {-m,--mount}'[description for "mount"]' \ "*:required argument:( ${required//[()]/} )"
- 替换
required argument
为您想要调用的任何参数。 - 填写选项的说明。
- 替换
- 再次确保该文件所在的目录位于您的
$fpath
. - 确保你
autoload -Uz compinit; compinit
在你的.zshrc
执行此操作并确保它运行后上面的目录已添加到您的$fpath
. - 重新启动你的 shell
exec zsh
或者关闭你的终端窗口并打开一个新窗口。
您现在应该能够完成myfunc
.
如果readonly
和mount
互斥,您需要重写完成函数的最后一行,如下所示:
_arguments \
(-m --mount){-r,--readonly}'[description for "readonly"]' \
(-r --readonly){-m,--mount}'[description for "mount"]' \
"*:required argument:( ${required//[()]/} )"