命令的补全系统tar
相当巧妙。当我有不同的存档类型时,它会根据使用的 tar 选项提供相关文件:
$ ls
file.tar.xz
file.tar.gz
$ tar xJf f<TAB>
file.tar.xz
$ tar xzf f<TAB>
file.tar.gz
它识别xJf
为对tar.xz
文件进行操作,并对文件xzf
进行操作。tar.gz
但是当目录存在于当前位置时,它也会提供它来完成:
$ tar xJf f<TAB>
foo/ file.tar.xz
我可以告诉完成系统,在提取档案时我只想完成文件(即tar
选项x...
)吗?
但在创建档案时它仍然应该提供目录(tar
选项c...
):
tar cpJf foo.tar.xz
我认为这需要修改tar
命令的主完成文件:/usr/share/zsh/functions/Completion/Unix/_tar
。但如何呢?
答案1
使完成系统仅显示以下文件每一个的调用
tar
相对简单。zstyle
添加此命令.zshrc
即可解决问题:
zstyle ':completion:*:*:tar:*' 'file-patterns' '*(.)'
这会触发内置函数中的代码_files
,通过 glob 限定符将文件模式匹配仅限于纯文件(.)
。
不幸的是,它会覆盖所有调用的模式匹配tar
,因此示例中基于扩展名的匹配不再起作用,并且在创建存档时目录不是匹配的一部分。更改zsh
为更有选择性地忽略目录涉及更深入地了解完成代码。
我们可以通过修改_tar_archive
函数来实现这一点(感谢@Gilles 指出如何实现)。该函数已经对提取档案和创建档案进行了单独的处理,因此我们只需要更改用于提取档案的行即可。
这是基于我的系统(macOS 10.15、zsh 5.7.1)中的代码修改后的代码。它_path_files
直接在提取案例中调用,因此它只查看文件。原始代码使用_files
,它循环遍历文件和目录。
#autoload
# This is used to generate filenames usable as a tar archive. This may
# get one argument, a collection of tar option characters that may be
# used to find out what kind of filename is needed. If no argument is
# given but the parameter `_tar_cmd' is set, that is used.
# If your version of `tar' supports this you may want to complete
# things like `host:file' or `user@host:file' here.
local expl
[[ $# -eq 0 && $+_tar_cmd -ne 0 ]] && set "$_tar_cmd"
_description files expl 'archive file'
if [[ "$1" = *[urtx]* ]]; then
if [[ "$1" = *[zZ]* ]]; then
_path_files "$expl[@]" -g '*.((tar|TAR).(gz|GZ|Z)|tgz)(-.)'
elif [[ "$1" = *[Ijy]* ]]; then
_path_files "$expl[@]" -g '*.(tar|TAR).bz2(-.)'
elif [[ "$1" = *J* ]]; then
_path_files "$expl[@]" -g '*.(tar|TAR).(lzma|xz)(-.)'
elif [[ "$_cmd_variant[$service]" == (gnu|libarchive) ]]; then
_path_files "$expl[@]" -g '*.((tar|TAR)(.gz|.GZ|.Z|.bz2|.lzma|.xz|)|(tbz|tgz|txz))(-.)'
else
_path_files "$expl[@]" -g '*.(tar|TAR)(-.)'
fi
else
_files "$expl[@]"
fi
修改完成系统中的功能可能有点棘手。最好创建副本,而不是更改原始目录中的发布代码。为了快速参考,这些是我的系统所需的命令;其他系统可能有不同的要求。此 Stack Exchange 答案中有更多详细信息: https://unix.stackexchange.com/a/33898/432774
一次改变:
mkdir ~/.zfunc
for d in $fpath; do
[[ -f $d/_tar_archive ]] && cp $d/_tar_archive ~/.zfunc; break
done
# (edit file as noted above)
print 'fpath=( ~/.zfunc "${fpath[@]}" )' >> ~/.zshrc
# (restart shell)
每次代码更改后都需要这些命令。请注意,仅重新启动 shell 可能还不够:
unfunction _tar_archive
autoload -Uz _tar_archive
rm ~/.zcompdump
rm ~/.zcompcache/*
compinit