Bash:从字符串变量的中间提取模式?

时间:2017-06-14 18:43:28

标签: bash built-in

我正在为命令foo编写自定义Bash完成函数。

您可以拨打foo --help并输出如下内容:

Usage: foo (start | stop | up | down) [options] [ARGS]

作为第一步,我希望我的完成功能解析此用法消息并抓取()之间的元素。我想尽可能多地使用shell内置函数,只有在绝对必要时才会生成sed之类的外部进程。现在我有:

_foo() {
  local cmd=$1 word=$2 usage=$(foo --help) subcmds

  [[ "$usage" =~ .*\((.*)\).* ]] && subcmds="${BASH_REMATCH[1]// |}"

  COMPREPLY=( $(compgen -W "$subcmds" -- "$word") )
}

complete -F _foo foo

这很有效,但是我想知道是否有一种方法可以在不诉诸=~BASH_REMATCH的情况下实现相同的结果,而只是组合参数字符串操作?

我可以将使用消息的一部分删除到打开的paren,

"${usage#*\(}"  # start | stop | up | down) [options] [ARGS]

我可以从结束时开始删除部分,

"${usage%)*}"   # Usage: foo (start | stop | up | down

但我不知道如何在不引入临时变量的情况下提取中间...

tmp="${usage#*\(}"
"${tmp%)*}"

我希望这样的东西可行,但没有运气

"${${usage#*\(}%)*}"

1 个答案:

答案 0 :(得分:3)

您可以在BASH替换中使用extglob来完成两个替换:

tmp='Usage: foo (start | stop | up | down) [options] [ARGS]'
echo "${tmp//@(*\(|\)*)}"

@(*\(|\)*)将匹配glob *()*,并将其替换为空字符串。

<强>输出:

start | stop | up | down

如果您想剥开管道,请使用:

echo "${tmp//@(*\(|\| |\)*)}"
start stop up down

(感谢OP)