Bash技巧:詳解用select複合命令的用法,可提供選擇菜單項

本篇文章介紹 bash 的 select 複合命令,該命令能夠提供菜單列表給用戶進行選擇。shell

  • select 命令格式
  • select 命令實例
  • 自定義提示信息
  • 修改菜單項的分割字符

select 命令格式

在 Linux 的 Bash shell 中,能夠用 select 複合命令 (compound command) 提供一個菜單列表給用戶選擇,並根據用戶的選擇進行相應地處理。查看 man bash 裏面對 select 命令的說明以下:bash

select name [ in word ] ; do list ; done
The list of words following "in" is expanded, generating a list of items. The set of expanded words is printed on the standard error, each preceded by a number. If the "in word" is omitted, the positional parameters are printed.

The PS3 prompt is then displayed and a line read from the standard input. If the line consists of a number corresponding to one of the displayed words, then the value of name is set to that word. If the line is empty, the words and prompt are displayed again. If EOF is read, the command completes. Any other value read causes name to be set to null. 函數

The line read is saved in the virable REPLY. The list is executed after each selection until a break command is executed. ui

The exit status of select is the exit status of the list command executed in list, or zero if no commands were executed.spa

select 命令格式中,[ in word ] 表示 "in word" 是可選參數,用於提供菜單列表,實際輸入的時候不須要輸入 [] 這兩個字符。而 name 變量會保存用戶選擇的菜單項內容,能夠獲取 name 變量值來查看用戶的選擇。每次用戶輸入選擇後,會執行 list 指定的命令。翻譯

注意:這裏的 [] 並非 bash 裏面的條件判斷命令。Bash 有一個 [ 條件判斷命令,其格式是 [ 參數... ],二者格式比較類似,注意區分,不要搞混。code

當沒有提供 in word 參數時,select 命令默認使用 in "$@" 參數,也就是傳入腳本、或者傳入函數的參數列表來做爲菜單選項。字符串

select 命令使用 in word 參數來指定菜單列表,不一樣的菜單項之間用空格隔開,不要用雙引號把整個菜單列表括起來,不然會被當成一個菜單項。input

當用雙引號把菜單列表括起來時,整個菜單列表被當成一個選項。若是某個選擇項的內容確實要包含空格,就能夠單獨用雙引號把這個選擇項的內容括起來,避免該選項該分割成多個選項。it

選擇以後,select 命令不會自動退出,而是等待用戶繼續選擇,須要執行 break 命令來退出,也能夠按 CTRL-D 來輸入EOF進行退出。輸入EOF退出後,name 變量值會保持以前的值不變,不會被自動清空。

select 命令的內部語句裏面,能夠用 exit 命令來直接退出整個腳本的執行,從而退出 select 的選擇。若是是在函數內調用 select 命令,則能夠用 return 命令來直接退出整個函數,從而退出 select 的選擇。

select 命令實例

假設有一個 testselect.sh 腳本,內容以下:

#!/bin/bash

select animal in lion tiger panda flower; do
    if [ "$animal" = "flower" ]; then
        echo "Flower is not animal."
        break
    else
        echo "Choose animal is: $animal"
    fi
done

echo "++++ Enter new select ++++"
select animal in "lion tiger panda"; do
    echo "Your choose is: $animal"
    break
done

這個腳本的第一個 select 命令定義了四個菜單項:liontigerpandaflower,若是用戶選擇了 flower 則執行 break 命令退出 select 的選擇,不然會打印出用戶選擇的動物名。

第二個 select 命令用雙引號把菜單選項括起來,以便查看加了雙引號後的效果。

執行該腳本,輸出結果以下:

$ ./testselect.sh
1) lion
2) tiger
3) panda
4) flower
#? 1
Choose animal is: lion
#? 2
Choose animal is: tiger
#? 7
Choose animal is:
#? lion
Choose animal is:
#? 4
Flower is not animal.
++++ Enter new select ++++
1) lion tiger panda
#? 1
Your choose is: lion tiger panda

能夠看到,select 命令要經過菜單項前面的數字來選擇對應的項,並把對應項的名稱賦值給指定的 animal 變量。

輸入菜單項自己的字符串並不能選擇這個菜單項。輸入無效的菜單項編號不會報錯。這兩種狀況都會把 animal 變量值清空。

自定義提示信息

上面的 #? 是 bash 的 PS3 提示符,咱們能夠爲 PS3 變量賦值,再執行 select 命令,從而打印自定義的提示信息。舉例以下:

$ PS3="Enjoy your choose:> "
$ select animal in lion tiger; do echo "Choose: $animal"; break; done
1) lion
2) tiger
Enjoy your choose:> 1
Choose: lion

能夠看到,爲 PS3 變量賦值後,select 命令會打印所賦值的內容,做爲提示符。

修改菜單項的分割字符

咱們能夠修改 bash 的 IFS 變量值,指定不一樣菜單項之間的分割字符,但在使用上有一個注意事項,具體說明以下:

$ IFS=/
$ animal_list="big lion/small tiger"
$ select animal in $animal_list; do echo "Choose: $animal"; break; done
1) big lion
2) small tiger
#? 1
Choose: big lion
$ select animal in big lion/small tiger; do echo "Choose: $animal"; break; done
1) big
2) lion/small
3) tiger
#? 2
Choose: lion/small

上面的例子把 IFS 賦值爲 /,而後定義 animal_list 變量,用 / 隔開了 big lionsmall tiger 兩項,用 select 命令從 animal_list 變量獲取菜單選項時,能夠看到再也不用空格來隔開選項,而是用 IFS 賦值後的 / 來隔開選項。

可是,當 select 命令不從 animal_list 變量獲取菜單選項,而是直接寫爲 select animal in big lion/small tiger 命令時,它仍是用空格來隔開選項,而不是用 IFS 賦值後的 / 來隔開選項。

緣由在於,IFS 用於 bash 擴展後的單詞拆分,使用 $animal_list 獲取 animal_list 變量值就是一種擴展,從而發生單詞拆分,用 IFS 的值來拆分紅幾個單詞。

直接寫爲 in big lion/small tiger 沒有發生擴展,因此沒有使用 IFS 來拆分單詞。

查看 man bash 對 IFS 的說明以下:

IFS
The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command. The default value is ``<space><tab><newline>''.

翻譯成中文就是,IFS (Internal Field Separator) 用於在擴展後進行單詞拆分,並使用 read 內置命令將行拆分爲單詞。

即,要在擴展以後,纔會用 IFS 的值來拆分單詞。

在經過 IFS 修改 select 命令的菜單項分割字符時,菜單列表須要保存到變量裏面,而後在 select 命令裏面獲取該變量值,進行變量擴展,IFS 纔會生效

相關文章
相關標籤/搜索