妥善处理在bash完成空格和引号 [英] Properly handling spaces and quotes in bash completion
问题描述
什么是处理空间和报价在bash完成正确的/最好的方法?
What is the correct/best way of handling spaces and quotes in bash completion?
下面是一个简单的例子。我有一个名为字命令
(例如,一个字典查找程序)采取各种文字作为参数。支持的'话'实际上可能包含空格,并在一个名为文件中定义 words.dat
:
Here’s a simple example. I have a command called words
(e.g., a dictionary lookup program) that takes various words as arguments. The supported ‘words’ may actually contain spaces, and are defined in a file called words.dat
:
foo
bar one
bar two
下面是我的第一个建议的解决方案:
Here’s my first suggested solution:
_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
键入'字F<标签>
正确完成命令'字富'
(后面有个空间),这是很好的,但对于'字b<标签>
这意味着话吧
。正确的完成将是'的话吧\\'
。和'字B<标签>
和'字'B<标签>
它不提供建议。
Typing ‘words f<tab>’
correctly completes the command to ‘words foo ’
(with a trailing space), which is nice, but for ‘words b<tab>’
it suggests ‘words bar ’
. The correct completion would be ‘words bar\ ’
. And for ‘words "b<tab>’
and ‘words 'b<tab>’
it offers no suggestions.
这最后一部分,我已经能够解决。它可以使用评估
来正确解析(转义)字符。然而,评估
是不喜欢丢失引号,所以把一切工作,我不得不改变搜索=$ CUR
为
This last part I have been able to solve. It’s possible to use eval
to properly parse the (escaped) characters. However, eval
is not fond of missing quotes, so to get everything to work, I had to change the search="$cur"
to
search=$(eval echo "$cur" 2>/dev/null ||
eval echo "$cur'" 2>/dev/null ||
eval echo "$cur\"" 2>/dev/null || "")
这实际工作。无论'字B&LT;标签&gt;
和'字'B&LT;标签&gt;
正确自动填充,如果我添加'O'
和preSS &LT;标签&gt;
再次,它实际上完成了字,并增加了正确的收盘报价不过,如果我尝试完成'字b&LT;标签&gt;
甚至'话吧\\&LT;标签&gt;
,它被自动补齐为话吧
而不是'的话吧\\'
,并添加例如一
会失败时,字
程序运行。
This actually works. Both ‘words "b<tab>’
and ‘words 'b<tab>’
correctly autocompletes, and if I add a ‘o’
and press <tab>
again, it actually completes the word and adds the correct closing quote. However, if I try to complete ‘words b<tab>’
or even ‘words bar\ <tab>’
, it is autocompleted to ‘words bar ’
instead of ‘words bar\ ’
, and adding for instance ‘one’
would fail when the words
program is run.
现在,显然的是的能够正确地处理这个问题。例如, LS
命令可以namned '富'
'栏文件之一做
和'栏两个
(尽管它与前pressing文件名的一些方法问题,当一个人使用(有效)两者的结合,
和各种逃脱),但我无法弄清楚如何 LS
通过阅读bash补code做的。
Now, obviously it is possible to handle this correctly. For instance, the ls
command can do it for files namned ‘foo’
‘bar one’
and ‘bar two’
(though it does have problems with some ways of expressing the filenames when one uses a (valid) combination of both "
, '
and various escapes). However, I couldn’t figure out how ls
does it by reading the bash completion code.
所以,没有任何人知道如何正确处理呢?实际输入引号不必是preserved;我将很高兴与变化'字B&LT;标签&gt;'的解决方案
,'字'B&LT;标签&gt;
和'字b&LT;标签&gt;
到'的话吧\\'
,例如,(虽然我愿意报价preFER剥离,像在本实施例中,代替将它们)。
So, does anybody know of how properly handle this? The actual input quotes need not be preserved; I would be happy with a solution that changes ‘words "b<tab>’
, ‘words 'b<tab>’
and ‘words b<tab>’
to ‘words bar\ ’
, for instance, (though I would prefer stripping of quotes, like in this example, instead of adding them).
推荐答案
这不是太优雅的后处理解决方案,似乎为我工作(GNU bash的版本3.1.17(6) - 释放(i686的-PC-cygwin的))。 (除非我没有测试一些边境情况下像往常一样:))
This not too elegant postprocessing solution seems to work for me (GNU bash, version 3.1.17(6)-release (i686-pc-cygwin)). (Unless I didn't test some border case as usual :))
不需要EVAL东西,只有2个类型的引号。
Don't need to eval things, there are only 2 kinds of quotes.
由于compgen并不想逃避为我们的空间,我们将难逃他们自己(只有字没有用引号开始)。这有完整列表的副作用(双选项卡上),具有溢出值也是如此。不知道这是好还是不好,因为LS没有做...
Since compgen doesn't want to escape spaces for us, we will escape them ourselves (only if word didn't start with a quote). This has a side effect of full list (on double tab) having escaped values as well. Not sure if that's good or not, since ls doesn't do it...
编辑:固定处理里面的话单,双qoutes。本质上讲,我们要通过3 unescapings :)。首先grep的,第二个用于compgen,并持续的话命令本身时自动完成就完成了。
Fixed to handle single and double qoutes inside the words. Essentially we have to pass 3 unescapings :). First for grep, second for compgen, and last for words command itself when autocompletion is done.
_find_words()
{
search=$(eval echo "$cur" 2>/dev/null || eval echo "$cur'" 2>/dev/null || eval echo "$cur\"" 2>/dev/null || "")
grep -- "^$search" words.dat | sed -e "{" -e 's#\\#\\\\#g' -e "s#'#\\\'#g" -e 's#"#\\\"#g' -e "}"
}
_words_complete()
{
local IFS=$'\n'
COMPREPLY=()
local cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=( $( compgen -W "$(_find_words)" -- "$cur" ) )
local escaped_single_qoute="'\''"
local i=0
for entry in ${COMPREPLY[*]}
do
if [[ "${cur:0:1}" == "'" ]]
then
# started with single quote, escaping only other single quotes
# [']bla'bla"bla\bla bla --> [']bla'\''bla"bla\bla bla
COMPREPLY[$i]="${entry//\'/${escaped_single_qoute}}"
elif [[ "${cur:0:1}" == "\"" ]]
then
# started with double quote, escaping all double quotes and all backslashes
# ["]bla'bla"bla\bla bla --> ["]bla'bla\"bla\\bla bla
entry="${entry//\\/\\\\}"
COMPREPLY[$i]="${entry//\"/\\\"}"
else
# no quotes in front, escaping _everything_
# [ ]bla'bla"bla\bla bla --> [ ]bla\'bla\"bla\\bla\ bla
entry="${entry//\\/\\\\}"
entry="${entry//\'/\'}"
entry="${entry//\"/\\\"}"
COMPREPLY[$i]="${entry// /\\ }"
fi
(( i++ ))
done
}
这篇关于妥善处理在bash完成空格和引号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!