双引号字符串中的Bash TAB自动补全

3

问题

我正在用C语言编写一个命令行Twitter客户端。我目前正在尝试为Twitter用户名实现TAB自动补全功能,如下所示:

tweet "@s<TAB>
@sourcebits @spolsky

但是,当字符串中间存在其他单词时,如下所示:

tweet "Foo bar @s<TAB>

Bash会将整个字符串视为一个单词,因此无法实现自动补全。在Bash手册中没有找到任何简单的解决方法,所以我决定绕过它。以下是我尚未完成的解决方案。我只是按空格拆分输入的字符串,取最后一个单词(暂时简化),然后将其发送给compgen(下面的变量$last_word)。但是,我需要在TAB自动补全产生的字符串开头附加$prefix,因为它替换了整个输入字符串(记住:它被视为一个单词)。这就是我的困境所在。

问题

如何解决这个问题?

代码等

__cltwitter_complete () {
  local cache="$HOME/.cltwitter_users.cache"
  local string=${COMP_WORDS[COMP_CWORD]}
  local last_word=${string##* }
  local prefix=${string% *}

  COMPREPLY=()

  #if [ ! -f ${cache} ] || [ "`find ${cache} -mmin +60`" != "" ]; then
  #  cltwitter-update-cache
  #fi

  if [[ "$last_word" == \"@* ]]; then  # if word is beginning of a quotation
    last_word=${last_word:2}
  elif [[ "$last_word" == @* ]]; then  # if user put '@' in front
    last_word=${last_word:1}
  fi

  COMPREPLY=( $( compgen -W "`cat $cache`" -P @ -- $last_word ) )
}

complete -F __cltwitter_complete tweet

Bash手册相关部分:

COMP_WORDS

一个数组变量(参见下面的Arrays),由当前命令行中单独的单词组成。这些单词是在shell元字符上进行分割,就像shell解析器将它们分开一样。此变量仅在由可编程完成工具调用的shell函数中可用。

2个回答

0

你真的需要引号吗?

例如,你的命令可以是:

tweet Foo bar @s<TAB>

那么@s就是你想要完成的单词,你可以搜索它。在脚本内部,你仍然可以使用$*来获取整个字符串。

现在你必须更加小心地调用,因为你不能再使用特殊字符如!和()而不需要用反斜杠进行转义。


我已经考虑过这个问题。基本上,这不是我希望做的事情,因为它感觉不对(在UNIX的意义上)。此外,由于可选地可以传递更多参数给可执行文件,因此消息现在必须是最后一个参数,因为它的长度是可变的,这变得很尴尬,因为它是唯一的强制性参数。 - Flygsand
通常,其他命令行实用程序通过使用带有破折号前缀的选项来解决此问题,然后使用分隔符(--),该分隔符表示“即使看起来像是选项,但在此之后的所有内容都是参数”。然后您仍然可以执行以下操作:tweet -x 我的推文很棒!tweet -x -- -此消息以破折号开头!tweet -- -这个也是。 - rix0rrr
啊,间距被评论系统搞砸了,但你明白我的意思。 - rix0rrr


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接