妥善处理在bash完成空格和引号 [英] Properly handling spaces and quotes in bash completion

查看:144
本文介绍了妥善处理在bash完成空格和引号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是处理空间和报价在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆