2017-06-14 55 views
1

我正在爲命令foo編寫自定義Bash完成功能。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%)*}" 

我wa š希望像這樣的工作,但沒有運氣

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

剛剛引進暫時的。沒關係。 – jrwren

回答

2

您可以使用extglob在BASH更換一個步驟獲得兩個替代:

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

@(*\(|\)*)將匹配glob的*()*和用空字符串替換它。

輸出:

start | stop | up | down 

如果你想要去除管道以及再使用:

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

(感謝OP)

+1

我喜歡這些路徑名擴展的特殊extglob情況。這裏很酷的東西是'@','*'或'+'會給出所需的輸出。 –

+1

不錯,這真的很聰明!在處理自定義bash完成時,打開'extglob'似乎是[常用操作](https://github.com/scop/bash-completion/blob/0845c2183c91054013055ca1966ec1e547fa5b13/bash_completion#L45),這很好理解。 – ivan

+1

我需要去掉管道'|'。這是不容易閱讀,但我最終: '「$ {tmp // @(* \(| \ | | \)*)}」' – ivan