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



我正在为命令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的情况下获得相同的结果,而只是组合参数字符串操作?

我可以删除使用消息的一部分,直到打开的括号,

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

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

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

但是我想不出一种在不引入临时变量的情况下只提取中间的方法......

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

我希望这样的事情会奏效,但没有运气

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

您可以在 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(

最新更新