【发布时间】:2019-03-04 12:06:33
【问题描述】:
在 bash 补全中处理空格和引号的正确/最佳方式是什么?
这是一个简单的例子。我有一个名为 words 的命令(例如,一个字典查找程序),它将各种单词作为参数。支持的“单词”实际上可能包含空格,并在名为 words.dat 的文件中定义:
foo
bar one
bar two
这是我的第一个建议解决方案:
_find_words()
{
search="$cur"
grep -- "^$search" words.dat
}
_words_complete()
{
local IFS=$'\n'
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=( $( compgen -W "$(_find_words)" -- "$cur" ) )
}
complete -F _words_complete words
输入‘words f<tab>’ 正确完成了对‘words foo ’ 的命令(带有尾随空格),这很好,但对于‘words b<tab>’,它建议‘words bar ’。正确的完成是‘words bar\ ’。对于‘words "b<tab>’ 和‘words 'b<tab>’,它不提供任何建议。
我已经能够解决最后一部分。可以使用eval 正确解析(转义)字符。但是,eval 不喜欢缺少引号,所以为了让一切正常工作,我不得不将 search="$cur" 更改为
search=$(eval echo "$cur" 2>/dev/null ||
eval echo "$cur'" 2>/dev/null ||
eval echo "$cur\"" 2>/dev/null || "")
这确实有效。 ‘words "b<tab>’ 和 ‘words 'b<tab>’ 都正确地自动完成,如果我添加 ‘o’ 并再次按 <tab>,它实际上会完成单词并添加正确的结束引号。但是,如果我尝试完成 ‘words b<tab>’ 甚至 ‘words bar\ <tab>’,它会自动完成为 ‘words bar ’ 而不是 ‘words bar\ ’,并且在运行 words 程序时添加 ‘one’ 会失败。
现在,显然 可以正确处理这个问题。例如,ls 命令可以对名为‘foo’ 和‘bar one’ 和‘bar two’ 的文件执行此操作(尽管当使用" 两者的(有效)组合时,它确实存在一些表达文件名的方法的问题,' 和各种转义)。但是,通过阅读 bash 完成代码,我无法弄清楚 ls 是如何做到的。
那么,有人知道如何正确处理这个问题吗?不需要保留实际的输入报价;例如,我会对将‘words "b<tab>’、‘words 'b<tab>’ 和‘words b<tab>’ 更改为‘words bar\ ’ 的解决方案感到满意(尽管我更喜欢像本例中那样去掉引号,而不是添加它们)。
【问题讨论】:
标签: bash autocomplete escaping eval quotes