Bash 补全详解
概述
在设计基于Bash的中文文件拼音补全的时候,需要高度定制的补全策略,于是特意研究了下Bash
的补全机制。
本文主要是man bash
里面相关说明,由于英文水平有限,参考了中文版的man
补全相关的 Shell 变量(Shell Variables)
COMP_CWORD
${COMP_WORDS} 的索引,指向当前光标位置所在的词。这个变量只有在被可编程补全功能 (参见下面的 Programmable Completion 章节) 调用的 shell 函数中才可用。
COMP_LINE
当前命令行。这个变量只有在被命令补全功能调用的 shell 函数和外部命令中才可用。
COMP_POINT
相对于当前命令起始处的当前光标位置。如果当前光标位置是当前命令的末端, 它的值就和 ${#COMP_LINE} 相等。 这个变量只有在被命令补全功能调用的 shell 函数和外部命令中才可用。
COMP_WORDS
一个数组变量 (参见下面的 Arrays(数组)一节),由当前命令行的各个单词构成。 这个变量只有在被命令补全功能调用的 shell 函数中才可用。
COMPREPLY
一个数组变量,bash 从中读取可能的命令补全。 它是由命令补全功能调用的 shell 函数产生的。
HOSTFILE
包含一个格式和/etc/hosts
相同的文件名,当 shell 需要补全主机名时要读取它。shell 运行过程中可以改变可能的主机名补全列表;改变之后下一次需要主机名补全时 bash 会将新文件的内容添加到旧列表中。如果定义了 HOSTFILE 但是没有赋值,bash 将尝试读取 /etc/hosts 文件来获得可能的主机名补全列表。当取消 HOSTFILE 的定义时,主机名列表将清空。
FIGNORE
一个冒号分隔的后缀名列表,在进行文件名补全时被忽略 (参见下面的 READLINE
章节)。一个后缀满足其中之一的文件名被排除在匹配的文件名之外。可以是这样: ".o:~".
GLOBIGNORE
一个冒号分隔的模式列表,定义了路径名扩展时要忽略的文件名集合。 如果一个文件名与路径扩展模式匹配,同时匹配 GLOBIGNORE
中的一个模式时,它被从匹配列表中删除。
可编程的补全(Programmable Completion)
当试图对一个命令的参数进行词的补全时,如果已经使用内建命令 complete
定义了这个命令的补全规则 (comspec),将启动可编程补全功能。
首先,命令名被确认。如果针对这个命令有补全规则的定义,那么将使用规则来产生可能的词的补全的列表。如果命令词是一个路径全名,将首先搜索针对这个路径全名的规则。如果针对这个路径全名没有找到规则,将尝试查找 针对最后一个斜杠后面的部分的规则。
一旦找到了一个规则,它将用作产生匹配的词。如果没有找到,将进行上面 Completing
中描述的 Bash
默认的补全。
首先,将执行规则指定的动作。只有以被补全的词开始的匹配词才会被返回。 当在文件或目录名补全中使用 -f 或 -d 选项时,shell 变量 FIGNORE
将用于对匹配进行过滤。
接下来,将产生所有由-G
选项给出的文件名扩展模式指定的补全。 模式产生的词不必匹配要补全的词。shell 变量 GLOBIGNORE
不会用于过滤匹配结果,但是变量 FIGNORE
会被使用。
接下来,将考虑 -W
选项的参数指定的字符串。这个字符串首先被划分,用特殊变量 IFS
中的字符作为分隔符。shell 引用被当作一个词。 接下来,每个词被扩展,使用上面 EXPANSION
中描述的 brace expansion, tilde expansion, parameter 和 variable expansion, command substitution, arithmetic expansion, 以及 pathname expansion 规则处理。对于结果,再使用上面 Word Splitting 中描述的规则划分成词。扩展的结果与要补全的词进行前部一致的比较,匹配的词成为可能的补全。
在这些匹配被产生后,任何由 -F
和 -C
选项指定的 shell 函数和命令将被执行。当命令或函数被执行时,变量 COMP_LINE
和 COMP_POINT
被赋值,使用上面 Shell Variables 中的规则。 如果要执行 shell 函数,还将设置变量 COMP_WORDS
和 COMP_CWORD
。当函数或命令被执行时,第一个参数是等待参数被补全的命令的名称,第二个参数是要补全的词,第三个参数是当前命令行中,要补全的词前面的词。对要补全的词产生的补全不会进行任何过滤;函数或命令在产生匹配时有完全的自由。
任何 -F
指定的函数将被首先执行。函数可以使用任何 shell 功能, 包含内建命令 compgen
,来产生匹配。它必须将可能的补全放到数组变量 COMPREPLY
中。
(博主注)例如: COMPREPLY=($(compgen -W "${fix_list}" -- "${cur}"))
接下来,任何 -C 选项指定的命令将被执行,其执行环境与命令替换 的环境相同。它应当向标准输出打印一个补全的列表,每行一个。 反斜杠可以用来转义一个新行符,如果需要的话。
所有可能的补全都产生之后,将对列表进行 -X
选项指定的任何过滤。过滤器是一个模式,和路径名扩展中的一样;模式中的 &
替换为要补全的词。字面上的 &
可以用反斜杠转义;反斜杠在进行匹配时被删除。任何匹配这个模式的补全将从列表中删除。前导的!
将使模式含义相反; 这种情况下,任何不匹配这个模式的补全将被删除。
最后,-P
和 -S
指定的任何前缀和后缀被添加到补全列表的每个成员后面,结果返回给 readline 补全代码,作为可能的补全列表。
如果先前执行的动作没有产生任何匹配,并且在定义 compspec 规则时,为 complete 命令提供了 -o dirname 选项,将尝试目录名补全。
默认情况下,如果找到了一个规则,它产生的任何东西都被返回给补全代码, 作为可能的补全的全集。不再尝试默认的 bash 补全,readline 默认的文件名补全也会禁止。如果定义规则时,为 complete 命令提供了 -o default
选项,在规则没有产生匹配时将进行 readline 默认的补全处理。
当一个规则指出期望目录名补全时,可编程补全函数强制 readline 在补全的名称后面添加一个斜杠,如果它是一个到目录的符号连接。然后还要经过 readline 变量 mark-directories 的值处理,不管 readline 变量 mark-symlinked-directories 的值是什么。
补全相关的 shell内建命令(SHELL BUILTIN COMMANDS)
compgen
compgen [option] [word]
根据 option
为 word
产生可能的补全。option
是 内建命令 complete
接受的任何选项,除了 -p
和 -r
,将匹配结果写到标准输出。 当使用 -F
或 -C
选项时,可编程补全功能所设置的多数 shell 变量如果存在,其值将不再有用。
产生的匹配与可编程补全代码根据补全规则加上相同的标志直接产生的结果相同。 如果指定了 word
,只有匹配 word
的补全结果将被显示出来。
返回值为真,除非提供了非法的选项,或者没有产生匹配。
complete
complete [-abcdefgjksuv] [-o comp-option] [-A action] [-G globpat] [-W wordlist] [-P prefix] [-S suffix] [-X filterpat] [-F function] [-C command] name [name ...] complete -pr [name ...]
指定每个 name 的参数应当如何被补全。如果给出了 -p 选项, 或者没有选项给出,现有的补全规则将被显示出来,以一种可以重用为输入 的格式显示。-r 选项将一个针对每个 name 的补全规则删除。或者,如果没有给出 name,将删除所有补全规则。
尝试词的补全时,应用这些补全规则的过程在上面 Programmable Completion(可编程补全) 中详述。
其他选项,如果给出的话,具有下列意义。-G, -W, 和 -X 选项的参数 (如果需要的话,还包括 -P 和 -S 选项) 应当被引用,避免在执行内建命令 complete 之前被扩展。
返回值为真,除非给出了非法的选项,给出除 -p 和 -r 之外 的某个选项时没有给出 name 参数,试图删除一条 name 的补全 规则但是规则不存在,或者添加补全规则时出错。
-o comp-option
comp-option 控制着 compspec 除了简单地产生补全之外的多种行为。 comp-option 可以是如下之一:
action | meaning |
---|---|
default | 使用 readline 的默认文件名补全,如果 compspec 没有得到匹配 |
dirnames | 进行目录名补全,如果 compspec 没有得到匹配 |
filenames | 告诉 readline,compspec 产生了文件名,使它可以进行任何文件名专用的处理 (例如,给目录名加上斜杠或消除尾部空白)。主要用于 shell 函数 |
nospace | 告诉 readline 不要向补全的词在行的最后添加一个空格 (这是默认行为) |
-A action
action 可以是下列之一,来产生一系列可能的补全结果:
action | meaning |
---|---|
alias | 起别名。也可以用 -a 指定 |
arrayvar | 数组变量名 |
binding Readline | 按键关联 |
builtin shell | 内建命令的名称。也可以用 -b 指定 |
command | 命令名。也可以用 -c 指定 |
directory | 目录名。也可以用 -d 指定 |
disabled | 被禁用的内建命令名称 |
enabled | 启用的内建命令名称 |
export | 被导出的 shell 变量名称。也可以用 -e 指定 |
file | 文件名。也可以用 -f 指定 |
function | shell 函数的名称 |
group | 组名。也可以用 -g 指定 |
helptopic | 内建命令 help 接受的帮助主题 |
hostname | 主机名,从环境变量 HOSTFILE 指定的文件中得到 |
job | 作业名,如果作业控制被激活的话。也可以用 -j 指定 |
keyword | shell 保留字。也可以用 -k 指定 |
running | 正在运行的作业名,如果作业控制被激活的话 |
service | 服务名。也可以用 -s 指定 |
setopt | 内建命令 set 的 -o 选项的有效参数 |
shopt | 内建命令 shopt 接受的 shell 选项名 |
signal | 信号名 |
stopped | 停止的作业名,如果作业控制被激活的话 |
user | 用户名。也可以用 -u 指定 |
variable | shell 变量的名称。也可以用 -v 指定 |
-G globpat
文件名扩展模式 globpat 被扩展,产生可能的补全。
-W wordlist
wordlist 被使用 IFS 特殊变量中的字符作为定界符来拆分,每个结果的词被扩展。可能的补全是结果列表 中匹配要补全的词的那一些。
-C command
command 将在一个子 shell 环境中执行,它的结果用作可能的补全。
-F function
shell 函数 function 将在当前 shell 环境中执行。当它结束时,可能 的补全可以从数组元素 COMPREPLY 中得到。
-X filterpat
filterpat 是一个模式,用于文件名扩展。所有前面的选项和参数产生 的可能的补全都要经过这一步处理,每一个匹配 filterpat 的补全都 被从列表中删除。为 filterpat 加上前导 ! 使模式意义相反;这种情况下,所有不匹配 filterpat 的模式被删除。
-P prefix
在所有其他选项都处理过之后,prefix 被加到每个可能的补全前面。
-S suffix
在所有其他选项都处理过之后,suffix 被加到每个可能的补全后面。
shopt
shopt [-pqsu] [-o] [optname ...]
对于控制可选的 shell 行为的变量,改变它们的值。没有选项或者有-P
选项时,将显示所有可设置的选项列表,以及它们是否已经设置的指示。-P
使得输出以一种可以被重用为输入的形式显示。
其他选项有如下含义:
-S
: 允许(设置) 每个 optname。-u
: 禁止(取消) 每个 optname。-q
: 禁止通常的输出 (安静模式);返回状态指示了 optname 是否被设置。 如果对 -q 给出了多个 optname 参数,如果所有 optname 都被允许,返回值就是 0; 否则返回非零值。-o
: 限制 optname 的值为内建命令 set 的 -o 选项定义的值。
如果使用 -s 或 -u 时没有给出 optname 参数,显示将分别限于被设置或被取消的选项。 除非另外说明,shopt 选项默认被禁止(取消)。
返回值在列出选项时是 0,如果所有 optname 都被允许的话,否则是非零值。 当设置或取消选项时,返回值是 0,除非 optname 是非法的 shell 选项。
shopt
选项的列表是:
- cdable_vars
如果设置的话,内建命令 cd 的参数如果不是目录,就假定是一个变量,它的值是要切换到的目录名。 - cdspell
如果设置的话, cd 命令中目录的细微拼写错误能够得以纠正。检查的错误包括字符错位,缺字符, 重复输入同一字符。如果找到了正确的值,将打印正确的文件名,命令将继续。 这个选项只能在交互 shell 中使用。 - hostcomplete
如果设置的话,并且正在使用 readline, bash 将试着对正在进行补全的包含 的词进行主机名补全 (参见上面的 READLINE 中的 Completing 段落)。这是默认允许的。 - no_empty_cmd_completion
如果设置的话,并且正在使用 readline, 试图在空行上执行补全时, bash 不会搜索 PATH 来查找可能的补全。 - nocaseglob
如果设置的话, bash 进行路径扩展时使用大小写不敏感方式匹配文件名(参见上面的 Pathname Expansion 路径扩展)。 - progcomp
如果设置的话,将启用可编程补全功能 (参见上面的 Programmable Completion)。 这个选项是默认启用的。 - ...
篇幅与文章主题的原因,不展开更多的shopt
列表介绍。