簡體   English   中英

打印出開關的所有情況的列表

[英]Print out a list of all cases of a switch

好奇的問題。 是否有可能在 bash 中自動打印出某個 switch-case 的所有情況? 在某種程度上,它盡可能保持可維護性,這意味着如果添加新案例以打印出相同的案例,則不必添加更多代碼。

例如,如果案例代表命令,這將很有用。 然后,幫助功能可以打印出所有可用的命令。

沒有直接的方法可以實現這一點,但您可以使用數組來維護您的選擇:

# Define your choices - be sure not to change their order later; only
# *append* new ones.
choices=( foo bar baz )

# Make the array elements the case branches *in order*.
case "$1" in
    "${choices[0]}")
        echo 'do foo'
        ;;

    "${choices[1]}")
        echo 'do bar'
        ;;

    "${choices[2]}")
        echo 'do baz'
        ;;

    *)
        echo "All choices: ${choices[@]}"

esac

這會降低分支的可讀性,但如果您仔細維護陣列,它是一個易於管理的解決方案。

請注意分支條件如何包含在"..." ,以防止 shell 將值解釋為 (glob-like) patterns

也就是說,正如chepner指出的那樣,也許您將您的選擇定義為匹配字符串變體的模式

在那種情況下:

  • choices數組中用引號定義模式; 例如, choices=( foo bar baz 'h*' )

  • case分支中不加引號地引用它; 例如, ${choices[3]})

bash不允許您訪問它解析的令牌,也不保存case字符串(也可以是 glob 表達式)。

不幸的是,這意味着您將無法以您希望的方式 DRY 代碼。

在將 Bash 4 的幾個特性組合在一起一段時間后,我得到了這個特性。

#!/bin/bash

set -euo pipefail 

# create coprocess with 2 descriptors so we can read and write to them
coproc CAT { cat ; }

# creme de la creme of this solution - use function to both collect and select elements
function element {
    echo "$1" >&${CAT[1]}
    echo "$1"
}   

case "$1" in
    $(element A))
            echo "Your choice is: A"
    ;;

    $(element B))
            echo "Your choice is: B"
    ;;

    *)
            echo "Your choice is not present in available options: $1"
            # close writing descriptor
            exec {CAT[1]}>&-
            #read colected options into an array
            mapfile -t OPTIONS <&${CAT[0]}

            echo "Available options are: [ ${OPTIONS[@]} ]"

    ;;
esac

輸出:

Your choice is not present in available options: C
Available options are: [ A B ]

此解決方案有 2 個部分:

  • coproc - 創建子進程以從子外殼讀取和寫入
  • 函數element ,它既寫入coproc進程的描述符並返回它的參數,這樣我們就可以在case ... esac使用它

如果處理所有選項都應該在case之外完成,那么您可以使用 Bash 4 case語句的;;&功能,它強制檢查case內的每個語句(通常 - 即;; - 它在第一次匹配后停止)。 需要進行此檢查,以便我們稍后可以將所有選項收集到一個數組中

可能有很多理由不使用它(可以安全地存儲在描述符中而不讀取它們的數據的限制是其中之一),我歡迎所有可以使這個解決方案更好的評論。

不知道我是否正確理解了您的問題,但是您可以執行 此頁面所說的操作,將所有可用案例打印為默認選擇:

case "$1" in
    start)
        start
        ;;

    stop)
        stop
        ;;

    status)
        status anacron
        ;;
    restart)
        stop
        start
        ;;
    condrestart)
        if test "x`pidof anacron`" != x; then
            stop
            start
        fi
        ;;

    *)
        echo $"Usage: $0 {start|stop|restart|condrestart|status}"
        exit 1

esac

您可以讓腳本自行檢查:

#!/bin/bash

case_start=$(("$LINENO" + 2))       #store line number of start
case "$1" in

    simple_case) echo "this is easy";;
    --tricky)
        echo "This is a tricky"
        (echo "Multiline")
        echo "Statement"
        ;;
    -h|--help) echo "heeeelp me";;
    -q|--quiet) ;;

    *) echo "unknown option";;
esac
case_end=$(("$LINENO" - 2))         #store line number of end

# - take lines between $case_start and $case_end
# - replace newlines with spaces
# - replace ";;" with newlines
# -=> now every case statement should be on its own line
# - then filter out cases: delete everything after the first ")" including the ")" and trim blanks
cases_available=`sed -n "${case_start},${case_end}p" $0 | sed 's/#.*//' | tr '\n' ' ' | sed 's/;;/\n/g' | sed 's/).*//;s/[[:blank:]]*//'`

echo -e "cases_available:\n\n$cases_available"

這將打印:

cases_available:
 
simple_case
--tricky
-h|--help
-q|--quiet
*

這有一些陷阱:

  • case 語句中帶有“;;”的注釋或字符串它會破壞東西
  • 無法處理嵌套的 switch case 語句。

我認為最好的方法以及在 OP 方面是將 switch case 結構實際打印到一個新文件中,然后在需要時將它的源文件中的源文件。

echo "case "'"$1"'" in" > case.sh
echo "  test)" >> case.sh
echo "    echo "This case!"" >> case.sh
echo "    ;;" >> case.sh
echo "esac" >> case.sh

chmod+x case.sh

./case.sh test

#This case!

通過這種方式,您可以輕松地使用變量來構建 switch/case 條件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM