Linux shell 腳本編程-高級篇 (二)

Linux shell 腳本編程-高級篇 (一)


2. 圖形化桌面環境中的腳本編程


 

2.1 創建文本菜單


創建交互式 shell 腳本最常用的方法是使用菜單。提供各種選項可以幫助腳本用戶瞭解腳本能做什麼和不能做什麼。
 

通常菜單腳本會清空顯示區域,然後顯示可用的選項列表。用戶可以按下與每個選項關聯的字母或數字來選擇選項。

shell 腳本菜單的核心是 case 命令。case 命令會根據用戶在菜單上的選擇來執行特定命令。


2.1.1 創建菜單佈局
-----------------------------------------------------------------------------------------------------------------------------------------
創建菜單的第一步顯然是決定在菜單上顯示哪些元素以及想要顯示的佈局方式。

在創建菜單前,通常要先清空顯示器上已有的內容。這樣就能在乾淨的、沒有干擾的環境中顯示菜單。

clear 命令用當前終端會話的 terminfo 數據來清理出現在屏幕上的文本。運行 clear 命令之後,可以用 echo 命令來顯示菜單元素。

默認情況下,echo 命令只顯示可打印文本字符。在創建菜單項時,非可打印字符通常也很有用,比如製表符和換行符。要在 echo 命令中包含這些字符,必
須使用 -e 選項。因此,命令如下:

    echo -e "1.\tDisplay disk space"
    
會生成如下輸出行:

    1.    Display disk space
    
這極大地方便了菜單項佈局的格式化。只需要幾個 echo 命令,就能創建一個看上去還行的菜單。

    clear
    echo
    echo -e "\t\t\tSys Admin Menu\n"
    echo -e "\t1. Display disk space"
    echo -e "\t2. Display logged on users"
    echo -e "\t3. Display memory usage"
    echo -e "\t0. Exit menu\n\n"
    echo -en "\t\tEnter option: "

最後一行的 -en 選項會去掉末尾的換行符。這讓菜單看上去更專業一些,光標會一直在行尾等待用戶的輸入。

創建菜單的最後一步是獲取用戶輸入。這步用 read 命令。因爲我們期望只有單字符輸入,所以在 read 命令中用了 -n 選項來限制只讀取一個字符。這樣
用戶只需要輸入一個數字,也不用按回車鍵:

    read -n 1 option

接下來,需要創建自己的菜單函數。


2.1.2 創建菜單函數
-----------------------------------------------------------------------------------------------------------------------------------------
shell 腳本菜單選項作爲一組獨立的函數實現起來更爲容易。這樣就能創建出簡潔、準確、容易理解的 case 命令。

要做到這一點,要爲每個菜單選項創建獨立的shell函數。創建 shell 菜單腳本的第一步是決定希望腳本執行哪些功能,然後將這些功能以函數的形式放在
代碼中。

通常會爲還沒有實現的函數先創建一個樁函數(stub function, 或者腳手架代碼)。樁函數是一個空函數,或者只有一個 echo 語句,說明最終這裏裏需要
什麼內容。

    function diskspace {
        clear
        echo "This is where the diskspace commands will go"
    }

這允許菜單在實現某個函數時仍然能正常操作。不需要寫出所有函數之後才能讓菜單投入使用。函數從 clear 命令開始。這樣就能在一個乾淨的屏幕上執行
該函數,不會受到原先菜單的干擾。

還有一點有助於製作 shell 腳本菜單,那就是將菜單佈局本身作爲一個函數來創建。

function menu {
    clear
    echo
    echo -e "\t\t\tSys Admin Menu\n"
    echo -e "\t1. Display disk space"
    echo -e "\t2. Display logged on users"
    echo -e "\t3. Display memory usage"
    echo -e "\t0. Exit program\n\n"
    echo -en "\t\tEnter option: "
    read -n 1 option
}

這樣一來,任何時候都能調用 menu 函數來重現菜單。


2.1.3 創建菜單函數
-----------------------------------------------------------------------------------------------------------------------------------------
現在已經建好了菜單佈局和函數,只需要創建程序邏輯將二者結合起來就行了,這需要用到case命令。

case 命令應該根據菜單中輸入的字符來調用相應的函數。用默認的 case 命令字符(*星號)來處理所有不正確的菜單項是種不錯的做法。

下面的代碼展示了典型菜單中 case 命令的用法:

    menu
    case $option in
    0)
        break ;;
    1)
        diskspace ;;
    2)
        whoseon ;;
    3)
        memusage ;;
    *)
        clear
        echo "Sorry, wrong selection";;
    esac

這段代碼首先用 menu 函數清空屏幕並顯示菜單。menu 函數中的 read 命令會一直等待,直到用戶在鍵盤上鍵入了字符。然後,case 命令就會接管餘下的
處理過程。case 命令會基於返回的字符調用相應的函數。在函數運行結束後,case 命令退出。


2.1.4 整合 shell 腳本菜單
-----------------------------------------------------------------------------------------------------------------------------------------
現在已經看到了構成shell腳本菜單的各個部分,將它們組合在一起,看看彼此之間是如何協作的。

示例:
    [devalone@devalone 18]$ cat menu1.sh
    #!/bin/bash
    # simple script menu

    function diskspace {
        clear
        df -h
    }

    function whoseon {
        clear
        who
    }

    function memusage {
        clear
        cat /proc/meminfo
    }

    function menu {
        clear
        echo
        echo -e "\t\t\tSys Admin Menu\n"
        echo -e "\t1. Display disk space"
        echo -e "\t2. Display logged on users"
        echo -e "\t3. Display memory usage"
        echo -e "\t0. Exit program\n\n"
        echo -en "\t\tEnter option: "
        read -n 1 option
    }

    while [ 1 ]
    do
        menu
        case $option in
            0)
                break ;;
            1)
                diskspace ;;
            2)
                whoseon ;;
            3)
                memusage ;;
            *)
                clear
                echo "Sorry, wrong selection" ;;
        esac
        echo -en "\n\n\t\t\tHit any key to continue"
        read -n 1 line
    done
    clear

運行:[devalone@devalone 18]$ ./menu1.sh


                        Sys Admin Menu

        1. Display disk space
        2. Display logged on users
        3. Display memory usage
        0. Exit program


                Enter option:


這個菜單創建了三個函數,利用常見的命令提取 Linux 系統的管理信息。它使用 while 循環來一直菜單,除非用戶選擇了選項 0,這時,它會用 break
命令來跳出 while 循環。


2.1.5 使用 select 命令
-----------------------------------------------------------------------------------------------------------------------------------------
可能已注意到,創建文本菜單的一半工夫都花在了建立菜單佈局和獲取用戶輸入。bash shell提供了一個很容易上手的小工具,幫助我們自動完成這些工作。

select 命令只需要一條命令就可以創建出菜單,然後獲取輸入的答案並自動處理。select 命令的格式如下:

    select variable in list
    do
        commands
    done

list 參數是由空格分隔的文本選項列表,這些列表構成了整個菜單。select 命令會將每個列表項顯示成一個帶編號的選項,然後爲選項顯示一個由 PS3
環境變量定義的特殊提示符。

示例:
    [devalone@devalone 18]$ cat smenu1.sh
    #!/bin/bash
    # using select in the menu

    function diskspace {
        clear
        df -h
    }

    function whoseon {
        clear
        who
    }

    function memusage {
        clear
        cat /proc/meminfo
    }


    PS3="Enter option:"

    select option in "Display disk space" "Display logged on users" "Display memory usage" "Exit program"

    do
        case $option in
            "Exit program")
                break ;;
            "Display disk space")
                diskspace ;;
            "Display logged on users")
                whoseon ;;
            "Display memory usage")
                memusage ;;
            *)
                clear
                echo "Sorry, wrong selection" ;;
        esac
    done
    clear

運行:
    [devalone@devalone 18]$ ./smenu1.sh
    1) Display disk space       3) Display memory usage
    2) Display logged on users  4) Exit program
    Enter option:4

在使用 select 命令時,存儲在變量中的結果值是整個文本字符串而不是跟菜單選項相關聯的數字。文本字符串值纔是要在 case 語句中進行比較的內容。


2.2 製作窗口
-----------------------------------------------------------------------------------------------------------------------------------------
dialog 包最早是由 Savio Lam 創建的一個小巧的工具,現在由 Thomas E. Dickey 維護。該包能夠用 ANSI 轉義控制字符在文本環境中創建標準的窗口對
話框。可以將這些對話框融入自己的 shell 腳本中,藉此與用戶進行交互。

    NOTE:
    -------------------------------------------------------------------------------------------------------------------------------------
    並非在所有的 Linux 發行版中都會默認安裝 dialog 包。如果未安裝可以根據自己系統包管理器功能安裝,下面是 Fedora 24 安裝指令:

    [devalone@devalone ~]$ sudo dnf install dialog
    
    

2.2.1 dialog 包
-----------------------------------------------------------------------------------------------------------------------------------------
dialog 命令使用命令行參數來決定生成哪種窗口部件(widget)。部件是 dialog 包中窗口元素類型的術語。dialog 包支持的部件類型如下表所示:


    dialog 部件
    +---------------+--------------------------------------------------------------------------------
    | 部 件            | 描 述
    +---------------+--------------------------------------------------------------------------------
    | calendar        | 提供選擇日期的日曆
    +---------------+--------------------------------------------------------------------------------
    | checklist        | 顯示多個選項(其中每個選項都能打開或關閉)
    +---------------+--------------------------------------------------------------------------------
    | form            | 構建一個帶有標籤以及文本字段(可以填寫內容)的表單
    +---------------+--------------------------------------------------------------------------------
    | fselect        | 提供一個文件選擇窗口來瀏覽選擇文件
    +---------------+--------------------------------------------------------------------------------
    | gauge            | 顯示完成的百分比進度條
    +---------------+--------------------------------------------------------------------------------
    | infobox        | 顯示一條消息,但不用等待迴應
    +---------------+--------------------------------------------------------------------------------
    | inputbox        | 提供一個輸入文本用的文本表單
    +---------------+--------------------------------------------------------------------------------
    | inputmenu        | 提供一個可編輯的菜單
    +---------------+--------------------------------------------------------------------------------
    | menu            | 顯示可選擇的一系列選項
    +---------------+--------------------------------------------------------------------------------
    | msgbox        | 顯示一條消息,並要求用戶選擇OK按鈕
    +---------------+--------------------------------------------------------------------------------
    | pause            | 顯示一個進度條來顯示暫定期間的狀態
    +---------------+--------------------------------------------------------------------------------
    | passwordbox    | 顯示一個文本框,但會隱藏輸入的文本
    +---------------+--------------------------------------------------------------------------------
    | passwordform    | 顯示一個帶標籤和隱藏文本字段的表單
    +---------------+--------------------------------------------------------------------------------
    | radiolist        | 提供一組菜單選項,但只能選擇其中一個
    +---------------+--------------------------------------------------------------------------------
    | tailbox        | 用tail命令在滾動窗口中顯示文件的內容
    +---------------+--------------------------------------------------------------------------------
    | tailboxbg        | 跟tailbox一樣,但是在後臺模式中運行
    +---------------+--------------------------------------------------------------------------------
    | textbox        | 在滾動窗口中顯示文件的內容
    +---------------+--------------------------------------------------------------------------------
    | timebox        | 提供一個選擇小時、分鐘和秒數的窗口
    +---------------+--------------------------------------------------------------------------------
    | yesno            | 提供一條帶有Yes和No按鈕的簡單消息
    +---------------+--------------------------------------------------------------------------------


要在命令行上指定某個特定的部件,需使用雙連字符格式:

    dialog --widget parameters
    
其中 widget 是上表中的部件名,parameters 定義了部件窗口的大小以及部件需要的文本。

每個dialog部件都提供了兩種形式的輸出:

    □ 使用STDERR
    □ 使用退出狀態碼

可以通過 dialog 命令的退出狀態碼來確定用戶選擇的按鈕。如果選擇了 Yes 或 OK 按鈕,dialog 命令會返回退出狀態碼 0。如果選擇了 Cancel 或 No
按鈕,dialog 命令會返回退出狀態碼 1。可以用標準的 $? 變量來確定 dialog 部件中具體選擇了哪個按鈕。

如果部件返回了數據,比如菜單選擇,那麼 dialog 命令會將數據發送到 STDERR。可以用標準的 bash shell 方法來將 STDERR 輸出重定向到另一個文件
或文件描述符中。

    dialog --inputbox "Enter your age:" 10 20 2>age.txt

這個命令會將文本框中輸入的文本重定向到 age.txt 文件中。


■ msgbox 部件
-----------------------------------------------------------------------------------------------------------------------------------------
msgbox 部件是對話框中最常見的類型。它會在窗口中顯示一條簡單的消息,直到用戶單擊 OK 按鈕後才消失。使用 msgbox 部件時要用下面的格式。

    dialog --msgbox text height width

text 參數是想在窗口中顯示的字符串。dialog 命令會根據由 height 和 width 參數創建的窗口的大小來自動換行。如果想在窗口頂部放一個標題,也可以
用 --title 參數,後接作爲標題的文本。

示例:

    dialog --title Testing --msgbox "This is a test" 10 20

如果終端仿真器支持鼠標,可以單擊 OK 按鈕來關閉對話框。也可以用鍵盤命令來模擬單擊動作——按下回車鍵。


■ yesno 部件
-----------------------------------------------------------------------------------------------------------------------------------------
yesno 部件進一步擴展了 msgbox 部件的功能,允許用戶對窗口中顯示的問題選擇 yes或 no。它會在窗口底部生成兩個按鈕:一個是 Yes,一個是No。用戶
可以用鼠標、製表符鍵或者鍵盤方向鍵來切換按鈕。要選擇按鈕的話,用戶可以按下空格鍵或者回車鍵。

示例:

    dialog --title "Please answer" --yesno "Is this thing on?" 10 20

dialog 命令的退出狀態碼會根據用戶選擇的按鈕來設置。如果用戶選擇了 No 按鈕,退出狀態碼是 1;如果選擇了 Yes按鈕,退出狀態碼就是 0。


■ inputbox 部件
-----------------------------------------------------------------------------------------------------------------------------------------
inputbox 部件爲用戶提供了一個簡單的文本框區域來輸入文本字符串。dialog 命令會將文本字符串的值發給 STDERR。必須重定向 STDERR來獲取用戶輸入。

inputbox提供了兩個按鈕:OK 和 Cancel。如果選擇了 OK 按鈕,命令的退出狀態碼就是 0;反之,退出狀態碼就會是 1。

示例:
    dialog --inputbox "Enter your age:" 10 20 2>age.txt
    [devalone@devalone 18]$ echo $?
    0
    [devalone@devalone 18]$ cat age.txt
    12[devalone@devalone 18]$

使用 cat 命令顯示文本文件的內容時,該值後面並沒有換行符。這能夠輕鬆地將文件內容重定向到 shell 腳本中的變量裏,以提取用戶輸入的字符串。


■ textbox 部件
-----------------------------------------------------------------------------------------------------------------------------------------
textbox 部件是在窗口中顯示大量信息的極佳辦法。它會生成一個滾動窗口來顯示由參數所指定的文件中的文本。

示例:
    [devalone@devalone 18]$ dialog --textbox /etc/passwd 15 45

/etc/passwd文件的內容會顯示在可滾動的文本窗口中。可以用方向鍵來左右或上下滾動顯示文件的內容。窗口底部的行會顯示當前查看的文本處於文件中的
哪個位置(百分比)。文本框只包含一個用來選擇退出部件的 Exit 按鈕。


■ menu 部件
-----------------------------------------------------------------------------------------------------------------------------------------
menu 部件允許創建之前所製作的文本菜單的窗口版本。只要爲每個選項提供一個選擇標號和文本就行了。

示例:
    [devalone@devalone 18]$ dialog --menu "Sys Admin Menu" 20 30 10 1 "Display disk space" 2 "Display users" \
    3 "Display memory usage" 4 "Exit" 2> test.txt

第一個參數定義了菜單的標題,之後的兩個參數定義了菜單窗口的高和寬,而第四個參數則定義了在窗口中一次顯示的菜單項總數。如果有更多的選項,可以
用方向鍵來滾動顯示它們。

在這些參數後面,必須添加菜單項對。第一個元素是用來選擇菜單項的標號。每個標號對每個菜單項應該是唯一的,可以通過在鍵盤上按下對應的鍵來選擇。
第二個元素是菜單中使用的文本。

如果用戶通過按下標號對應的鍵選擇了某個菜單項,該菜單項會高亮顯示但不會被選定。直到用戶用鼠標或回車鍵選擇了 OK 按鈕時,選項纔會最終選定。
dialog 命令會將選定的菜單項文本發送到 STDERR。可以根據需要重定向 STDERR。


■ fselect 部件
-----------------------------------------------------------------------------------------------------------------------------------------
fselect 部件在處理文件名時非常方便。不用強制用戶鍵入文件名,就可以用 fselect 部件來瀏覽文件的位置並選擇文件。

示例:
    
    [devalone@devalone 18]$ dialog --title "Select a file" --fselect $HOME/ 10 50 2>file.txt

fselect 選項後的第一個參數是窗口中使用的起始目錄位置。fselect 部件窗口由左側的目錄列表、右側的文件列表(顯示了選定目錄下的所有文件)和含有
當前選定的文件或目錄的簡單文本框組成。可以手動在文本框鍵入文件名,或者用目錄和文件列表來選定(使用空格鍵選擇文件,將其加入文本框中)。


2.2.2 dialog 選項
-----------------------------------------------------------------------------------------------------------------------------------------
除了標準部件,還可以在 dialog 命令中定製很多不同的選項。已經看過了 —title 選項的用法。它允許設置出現在窗口頂部的部件標題。

另外還有許多其他的選項可以讓程序員全面定製窗口外觀和操作。dialog 命令中可用的選項如下表所示:


    dialog 命令選項
    +---------------------------+----------------------------------------------------------------------------
    | 選 項                        | 描 述
    +---------------------------+----------------------------------------------------------------------------
    | --add-widget                | 繼續下個對話框,直到按下Esc或Cancel按鈕
    +---------------------------+----------------------------------------------------------------------------
    | --aspect ratio            | 指定窗口寬度和高度的寬高比
    +---------------------------+----------------------------------------------------------------------------
    | --backtitle title            | 指定顯示在屏幕頂部背景上的標題
    +---------------------------+----------------------------------------------------------------------------
    | --begin x y                | 指定窗口左上角的起始位置
    +---------------------------+----------------------------------------------------------------------------
    | --cancel-label label        | 指定Cancel按鈕的替代標籤
    +---------------------------+----------------------------------------------------------------------------
    | --clear                    | 用默認的對話背景色來清空屏幕內容
    +---------------------------+----------------------------------------------------------------------------
    | --colors                    | 在對話文本中嵌入ANSI色彩編碼
    +---------------------------+----------------------------------------------------------------------------
    | --cr-wrap                    | 在對話文本中允許使用換行符並強制換行
    +---------------------------+----------------------------------------------------------------------------
    | --create-rc file            | 將示例配置文件的內容複製到指定的file文件中
    +---------------------------+----------------------------------------------------------------------------
    | --defaultno                | 將yes/no對話框的默認答案設爲No
    +---------------------------+----------------------------------------------------------------------------
    | --default-item string        | 設定複選列表、表單或菜單對話中的默認項
    +---------------------------+----------------------------------------------------------------------------
    | --exit-label label        | 指定Exit按鈕的替代標籤
    +---------------------------+----------------------------------------------------------------------------
    | --extra-button            | 在OK按鈕和Cancel按鈕之間顯示一個額外按鈕
    +---------------------------+----------------------------------------------------------------------------
    | --extra-label label        | 指定額外按鈕的替代標籤
    +---------------------------+----------------------------------------------------------------------------
    | --help                    | 顯示dialog命令的幫助信息
    +---------------------------+----------------------------------------------------------------------------
    | --help-button                | 在OK按鈕和Cancel按鈕後顯示一個Help按鈕
    +---------------------------+----------------------------------------------------------------------------
    | --help-label label        | 指定Help按鈕的替代標籤
    +---------------------------+----------------------------------------------------------------------------
    | --help-status                | 當選定Help按鈕後,在幫助信息後寫入多選列表、單選列表或表單信息
    +---------------------------+----------------------------------------------------------------------------
    | --ignore                    | 忽略dialog不能識別的選項
    +---------------------------+----------------------------------------------------------------------------
    | --input-fd fd                | 指定STDIN之外的另一個文件描述符
    +---------------------------+----------------------------------------------------------------------------
    | --insecure                | 在password部件中鍵入內容時顯示星號
    +---------------------------+----------------------------------------------------------------------------
    | --item-help                | 爲多選列表、單選列表或菜單中的每個標號在屏幕的底部添加一個幫助欄
    +---------------------------+----------------------------------------------------------------------------
    | --keep-window                | 不要清除屏幕上顯示過的部件
    +---------------------------+----------------------------------------------------------------------------
    | --max-input size            | 指定輸入的最大字符串長度。默認爲2048
    +---------------------------+----------------------------------------------------------------------------
    | --nocancel                | 隱藏Cancel按鈕
    +---------------------------+----------------------------------------------------------------------------
    | --no-collapse                | 不要將對話文本中的製表符轉換成空格
    +---------------------------+----------------------------------------------------------------------------
    | --no-kill                    | 將tailboxbg對話放到後臺,並禁止該進程的SIGHUP信號
    +---------------------------+----------------------------------------------------------------------------
    | --no-label label            | 爲No按鈕指定替代標籤
    +---------------------------+----------------------------------------------------------------------------
    | --no-shadow                | 不要顯示對話窗口的陰影效果
    +---------------------------+----------------------------------------------------------------------------
    | --ok-label label            | 指定OK按鈕的替代標籤
    +---------------------------+----------------------------------------------------------------------------
    | --output-fd fd            | 指定除STDERR之外的另一個輸出文件描述符
    +---------------------------+----------------------------------------------------------------------------
    | --print-maxsize            | 將對話窗口的最大尺寸打印到輸出中
    +---------------------------+----------------------------------------------------------------------------
    | --print-size                | 將每個對話窗口的大小打印到輸出中
    +---------------------------+----------------------------------------------------------------------------
    | --print-version            | 將dialog的版本號打印到輸出中
    +---------------------------+----------------------------------------------------------------------------
    | --separate-output            | 一次一行地輸出checklist部件的結果,不使用引號
    +---------------------------+----------------------------------------------------------------------------
    | --separator string        | 指定用於分隔部件輸出的字符串
    +---------------------------+----------------------------------------------------------------------------
    | --separate-widget string    | 指定用於分隔部件輸出的字符串
    +---------------------------+----------------------------------------------------------------------------
    | --shadow                    | 在每個窗口的右下角繪製陰影
    +---------------------------+----------------------------------------------------------------------------
    | --single-quoted            | 需要時對多選列表的輸出採用單引號
    +---------------------------+----------------------------------------------------------------------------
    | --sleep sec                | 在處理完對話窗口之後延遲指定的秒數
    +---------------------------+----------------------------------------------------------------------------
    | --stderr                    | 將輸出發送到STDERR(默認行爲)
    +---------------------------+----------------------------------------------------------------------------
    | --stdout                    | 將輸出發送到STDOUT
    +---------------------------+----------------------------------------------------------------------------
    | --tab-correct                | 將製表符轉換成空格
    +---------------------------+----------------------------------------------------------------------------
    | --tab-len n                | 指定一個製表符佔用的空格數(默認爲8)
    +---------------------------+----------------------------------------------------------------------------
    | --timeout sec                | 指定無用戶輸入時,sec秒後退出並返回錯誤代碼
    +---------------------------+----------------------------------------------------------------------------
    | --title title                | 指定對話窗口的標題
    +---------------------------+----------------------------------------------------------------------------
    | --trim                    | 從對話文本中刪除前導空格和換行符
    +---------------------------+----------------------------------------------------------------------------
    | --visit-items                | 修改對話窗口中製表符的停留位置,使其包括選項列表
    +---------------------------+----------------------------------------------------------------------------
    | --yes-label label            | 爲Yes按鈕指定替代標籤
    +---------------------------+----------------------------------------------------------------------------

--backtitle 選項是爲腳本中的菜單創建公共標題的簡便辦法。如果爲每個對話窗口都指定了該選項,那麼它在應用中就會保持一致,這樣會讓腳本看起來
更專業。

可以重寫對話窗口中的任意按鈕標籤。該特性允許創建任何需要的窗口。

 

2.2.3 在腳本中使用 dialog 命令
-----------------------------------------------------------------------------------------------------------------------------------------
在腳本中使用 dialog 命令必須記住兩件事:

    ● 如果有 Cancel 或 No 按鈕,檢查 dialog 命令的退出狀態碼;
    ● 重定向 STDERR 來獲得輸出值。

示例:
    [devalone@devalone 18]$ cat menu3.sh
    #!/bin/bash
    # using dialog to create a menu

    temp=$(mktemp -t test.XXXXXX)
    temp2=$(mktemp -t test2.XXXXXX)

    function diskspace {
            df -k > $temp
            dialog --textbox $temp 20 60
    }

    function whoseon {
            who > $temp
            dialog --textbox $temp 20 50
    }

    function memusage {
            cat /proc/meminfo > $temp
            dialog --textbox $temp 20 50
    }

    while [ 1 ]
    do
            dialog --menu "Sys Admin Menu" 20 30 10 1 "Display disk space" 2 "Display users" 3 "Display memory usage" 0 "Exit" 2> $temp2
            if [ $? -eq 1 ]
            then
                    break
            fi

            selection=$(cat $temp2)

            case $selection in
            1)
                    diskspace ;;
            2)
                    whoseon ;;
            3)
                    memusage ;;
            0)
                    break ;;
            *)
                    dialog --msgbox "Sorry, invalid selection" 10 30
            esac
    done

    rm -f $temp 2> /dev/null
    rm -f $temp2 2> /dev/null

這段腳本用 while 循環和一個真值常量創建了個無限循環來顯示菜單對話。這意味着,執行完每個函數之後,腳本都會返回繼續顯示菜單。

由於 menu 對話包含了一個 Cancel 按鈕,腳本會檢查 dialog 命令的退出狀態碼,以防用戶按下 Cancel 按鈕退出。因爲它是在 while 循環中,所以退出
該菜單就跟用 break 命令跳出 while 循環一樣簡單。

腳本用 mktemp 命令創建兩個臨時文件來保存 dialog 命令的數據。第一個臨時文件 $temp用

來保存 df 和 meminfo 命令的輸出,這樣就能在 textbox 對話中顯示它們。第二個臨時文件 $temp2 用來保存在主菜單對話中選定的值。

運行:
    [devalone@devalone 18]$ menu3.sh

 

2.3 使用圖形
-----------------------------------------------------------------------------------------------------------------------------------------
如果想給交互腳本加入更多的圖形元素,可以再進一步。KDE 和 GNOME 桌面環境都擴展了 dialog 命令的思路,包含了可以在各自環境下生成 X Window
圖形化部件的命令。


2.3.1 KDE 環境
-----------------------------------------------------------------------------------------------------------------------------------------
KDE 圖形化環境默認包含 kdialog包。kdialog 包使用 kdialog 命令在 KDE 桌面上生成類似於 dialog 式部件的標準窗口。生成的窗口能跟其他 KDE 應用
窗口很好地融合,不會造成不協調的感覺。這樣就可以直接在 shell 腳本中創建能夠和 Windows相媲美的用戶界面了。


■ kdialog 部件
-----------------------------------------------------------------------------------------------------------------------------------------
就像 dialog 命令,kdialog 命令使用命令行選項來指定具體使用哪種類型的窗口部件。下面是 kdialog 命令的格式:

    kdialog display-options window-options arguments

window-options 選項允許指定使用哪種類型的窗口部件。可用的選項如下表所示:


    kdialog 窗口選項
    +---------------------------------------+--------------------------------------------------------------------------
    | 選 項                                    | 描 述
    +---------------------------------------+--------------------------------------------------------------------------
    | --checklist title [tag item status]    | 帶有狀態的多選列表菜單,可以表明選項是否被選定
    +---------------------------------------+--------------------------------------------------------------------------
    | --error text                            | 錯誤消息框
    +---------------------------------------+--------------------------------------------------------------------------
    | --inputbox text [init]                | 輸入文本框。可以用init值來指定默認值
    +---------------------------------------+--------------------------------------------------------------------------
    | --menu title [tag item]                | 帶有標題的菜單選擇框,以及用tag標識的選項列表
    +---------------------------------------+--------------------------------------------------------------------------
    | --msgbox text                            | 顯示指定文本的簡單消息框
    +---------------------------------------+--------------------------------------------------------------------------
    | --password text                        | 隱藏用戶輸入的密碼輸入文本框
    +---------------------------------------+--------------------------------------------------------------------------
    | --radiolist title [tag item status]    | 帶有狀態的單選列表菜單,可以表明選項是否被選定
    +---------------------------------------+--------------------------------------------------------------------------
    | --separate-output                        | 爲多選列表和單選列表菜單返回按行分開的選項
    +---------------------------------------+--------------------------------------------------------------------------
    | --sorry text                            | “對不起”消息框
    +---------------------------------------+--------------------------------------------------------------------------
    | --textbox file [width] [height]        | 顯示file的內容的文本框,可以指定width和height
    +---------------------------------------+--------------------------------------------------------------------------
    | --title title                            | 爲對話窗口的TitleBar區域指定一個標題
    +---------------------------------------+--------------------------------------------------------------------------
    | --warningyesno text                    | 帶有Yes和No按鈕的警告消息框
    +---------------------------------------+--------------------------------------------------------------------------
    | --warningcontinuecancel text            | 帶有Continue和Cancel按鈕的警告消息框
    +---------------------------------------+--------------------------------------------------------------------------
    | --warningyesnocancel text                | 帶有Yes、No和Cancel按鈕的警告消息框
    +---------------------------------------+--------------------------------------------------------------------------
    | --yesno text                            | 帶有Yes和No按鈕的提問框
    +---------------------------------------+--------------------------------------------------------------------------
    | --yesnocancel text                    | 帶有Yes、No和Cancel按鈕的提問框
    +---------------------------------------+--------------------------------------------------------------------------
    
在使用 kdialog 窗口部件時,它看起來更像是KDE桌面上的一個獨立窗口,而不是在終端仿真器會話中的。checklist 和r adiolist 部件允許在列表中
定義單獨的選項以及它們默認是否選定。

示例:

    kdialog --checklist "Items I need" 1 "Toothbrush" on 2 "Toothpaste" off 3 "Hair brush" on 4 "Deodorant" off 5 "Slippers" off

指定爲 on 的選項會在多選列表中高亮顯示。要選擇或取消選擇多選列表中的某個選項,只要單擊它就行了。如果選擇了 OK 按鈕,kdialog 就會將標號值
發到 STDOUT上。

當按下回車鍵時,kdialog 窗口就和選定選項一起出現了。當單擊 OK 或 Cancel 按鈕時,kdialog 命令會將每個標號作爲一個字符串值返回到 STDOUT
(這些就是在輸出中看到的 "1" 和 "3")。腳本必須能解析結果值並將它們和原始值匹配起來。


■ 使用 kdialog
-----------------------------------------------------------------------------------------------------------------------------------------
可以在 shell 腳本中使用 kdialog 窗口部件,方法類似於 dialog 部件。最大的不同是 kdialog 窗口部件用 STDOUT 來輸出值,而不是 STDERR。

示例:
    $ cat menu4
    #!/bin/bash
    # using kdialog to create a menu
    
    temp=$(mktemp -t temp.XXXXXX)
    temp2=$(mktemp -t temp2.XXXXXX)
    
    function diskspace {
        df -k > $temp
        kdialog --textbox $temp 1000 10
    }
    
    function whoseon {
        who > $temp
        kdialog --textbox $temp 500 10
    }
    
    function memusage {
        cat /proc/meminfo > $temp
        kdialog --textbox $temp 300 500
    }
    
    while [ 1 ]
    do
        kdialog --menu "Sys Admin Menu" "1" "Display diskspace" "2" "Display users" "3" "Display memory usage" "0" "Exit" > $temp2
        
        if [ $? -eq 1 ]
        then
            break
        fi
        
        selection=$(cat $temp2)
        
        case $selection in
        1)
            diskspace ;;
        2)
            whoseon ;;
        3)
            memusage ;;
        0)
            break ;;
        *)
            kdialog --msgbox "Sorry, invalid selection"
        esac
    done


2.3.2 GNOME 環境
-----------------------------------------------------------------------------------------------------------------------------------------
GNOME 圖形化環境支持兩種流行的可生成標準窗口的包:

    □ gdialog
    □ zenity

zenity 是大多數 GNOME桌面 Linux 發行版上最常見的包(在 Ubuntu 和 Fedora 上默認安裝)


■ zenity 部件
-----------------------------------------------------------------------------------------------------------------------------------------
zenity 允許用命令行選項創建不同的窗口部件。下表列出了zenity 能夠生成的不同部件。


    zenity 窗口部件
    +-------------------+---------------------------------------------------------------------------
    | 選 項                | 描 述
    +-------------------+---------------------------------------------------------------------------
    | --calendar        | 顯示一整月日曆
    +-------------------+---------------------------------------------------------------------------
    | --entry            | 顯示文本輸入對話窗口
    +-------------------+---------------------------------------------------------------------------
    | --error            | 顯示錯誤消息對話窗口
    +-------------------+---------------------------------------------------------------------------
    | --file-selection    | 顯示完整的路徑名和文件名對話窗口
    +-------------------+---------------------------------------------------------------------------
    | --info            | 顯示信息對話窗口
    +-------------------+---------------------------------------------------------------------------
    | --list            | 顯示多選列表或單選列表對話窗口
    +-------------------+---------------------------------------------------------------------------
    | --notification    | 顯示通知圖標
    +-------------------+---------------------------------------------------------------------------
    | --progress        | 顯示進度條對話窗口
    +-------------------+---------------------------------------------------------------------------
    | --question        | 顯示yes/no對話窗口
    +-------------------+---------------------------------------------------------------------------
    | --scale            | 顯示可調整大小的窗口
    +-------------------+---------------------------------------------------------------------------
    | --text-info        | 顯示含有文本的文本框
    +-------------------+---------------------------------------------------------------------------
    | --warning            | 顯示警告對話窗口
    +-------------------+---------------------------------------------------------------------------

zenity 命令行程序與 kdialog 和 dialog 程序的工作方式有些不同。許多部件類型都用另外的命令行選項定義,而不是作爲某個選項的參數。

zenity 命令能夠提供一些非常酷的高級對話窗口。calendar 選項會產生一個整月的日曆,當在日曆中選擇了日期時,zenity 命令會將值返回到 STDOUT 中。


■ 在腳本中使用 zenity
-----------------------------------------------------------------------------------------------------------------------------------------
zenity 在 shell 腳本中表現良好。

示例:

    $cat menu5
    #!/bin/bash
    # using zenity to create a menu

    temp=$(mktemp -t temp.XXXXXX)
    temp2=$(mktemp -t temp2.XXXXXX)

    function diskspace {
        df -k > $temp
        zenity --text-info --title "Disk space" --filename=$temp
        --width 750 --height 10
    }

    function whoseon {
        who > $temp
        zenity --text-info --title "Logged in users" --filename=$temp
        --width 500 --height 10
    }

    function memusage {
        cat /proc/meminfo > $temp
        zenity --text-info --title "Memory usage" --filename=$temp
        --width 300 --height 500
    }

    while [ 1 ]
    do
        zenity --list --radiolist --title "Sys Admin Menu" --column "Select" --column "Menu Item" FALSE "Display diskspace" FALSE \
        "Display users" FALSE "Display memory usage" FALSE "Exit" > $temp2
        
        if [ $? -eq 1 ]
        then
            break
        fi
        
        selection=$(cat $temp2)
        
        case $selection in
        "Display disk space")
            diskspace ;;
        "Display users")
            whoseon ;;
        "Display memory usage")
            memusage ;;
        Exit)
            break ;;
        *)
            zenity --info "Sorry, invalid selection"
        esac
    done

由於 zenity 並不支持菜單對話窗口,改用單選列表窗口來作爲主菜單。

該單選列表用了兩列,每列都有一個標題:第一列包含用於選擇的單選按鈕,第二列是選項文本。單選列表也不用選項裏的標號。當選定一個選項時,該
選項的所有文本都會返回到 STDOUT。這會讓 case 命令的內容豐富一些。必須在 case 中使用選項的全文本。如果文本中有任何空格,要給文本加上引號。

 

 

系列目錄:

Linux shell 腳本編程-高級篇 (一)

Linux shell 腳本編程-高級篇 (二)

Linux shell 腳本編程-高級篇 (三)

Linux shell 腳本編程-高級篇 (四)

Linux shell 腳本編程-高級篇 (五)

Linux shell 腳本編程-高級篇 (六)

Linux shell 腳本編程-高級篇 (七)

 

 

-----------------------------------------------------------------------------------------------------------------------------------------
參考:

    《Linux 命令行與 shell 腳本編程大全》 第 3 版 —— 2016.8(美)Richard Blum  Cristine Bresnahan

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章