假设我希望导出一个名为MYPATH
holding以下2个路径的环境变量:
- /完整/路径/到/fileA
- /另一个/完整/路径/到/fileB
所以,我认为应该在 bash 中这样做:
$export MYPATH=/full/path/to/fileA:/another/full/path/to/fileB
我面临的问题是自动完成(Tab键)在命令中写入路径 A 时起作用,但在:
自动完成停止工作后,因此在没有自动完成的情况下很难在控制台中写入路径 B。
令人惊讶的是,如果满足以下条件,它就会起作用:
- 我使用分号而不是冒号,但这无论如何都不是正确的路径分隔符。
- 我是root用户。
有人可以解释这种行为的原因吗?
- Bash 版本:GNU bash,版本 4.3.48(1)-release (x86_64-pc-linux-gnu)
- Bash 完成版本:all/xenial-updates 1:2.1-4.2ubuntu1.1
- 操作系统版本:Ubuntu 16.04.6 LTS
答案1
您所描述的行为可能是由bash 完成。
(以下内容基于该包的当前版本 (2.9),但对于您拥有的 2.1 版本来说也相当准确)。
bash-completion 提供了一组完成规范(比较规范),Readline 库使用它来完成作为 Bash 中命令的参数提供的单词。它们是使用以下定义的complete
内置命令,通常采用以下形式:
complete -F function command
对于export
内置函数,该函数_export
在 中定义/usr/share/bash-completion/completions/export
。
当要完成的单词包含(或以 a 结尾)时=
,_export
尝试将其完成(实际上是第一个 右侧的部分=
)作为文件或目录名;当要补全的单词不包含 a 时=
,它会尝试将其补全为变量名。由于 Readline 库每次遇到变量中列出的一个字符COMP_WORDBREAKS
(除非该字符被转义)(通常包括 )时都会启动一个新的完成,因此:
在附加到变量值的第一个冒号之后,完成将停止工作,因为此时,重点是,要完成的单词不再包含(或以)a 结尾=
。 (顺便请注意,如果您写入并点击 ,
文件/目录名称补全将再次开始工作)。export myvar=/usr/:othervar=
Tab
bash-completion 确实有自己的处理特殊情况的机制。例如,:
由 compspec for 正确处理scp
,它将冒号右侧的内容解释为远程路径。但同样的情况不适用于export
。
阅读线的默认行为,当未找到当前命令的 compspec 时触发,最终是尝试文件名完成。这就是为什么在未安装 bash-completion 或以其他方式禁用 bash-completion 时完成path2
in起作用的原因(请记住每个冒号都会启动一个新的完成)。export var=/path1/:/path2/
那你能做什么呢?您有一些替代方案:
将功能请求提交至GitHub 上的 bash-completion。
定义您自己的补全函数
export
。
首先,将 compspec 复制到用户完成文件(该文件可能尚不存在):$ cat /usr/share/bash-completion/completions/export >>~/.bash_completion
然后编辑
~/.bash_completion
,complete -F _export export
改为complete -F _export -o default export
.export
当 的特定 compspec 没有给出结果时,这指示 Readline 尝试默认完成。使用默认补全,而不是 bash-completion 提供的补全。
添加到您的~/.bashrc
:complete -o default -o bashdefault export
(建议来自bash-completion 的常见问题解答)。缺点是您无法完成变量名称和
export
选项。如果您愿意足够熟悉 bash-completion,请定义您自己的
_export
函数,如 (2) 中所示,通过编辑提供的函数以使其进行:
特殊处理。