多年來, shell腳本一直都被認為是枯燥乏味的。但如果你準備在圖形化環境中運行腳本時,就未必如此了。有很多與腳本用戶交互的方式并不依賴read和echo語句。
9.1 創建文本菜單
創建交互式shell腳本最常用的方法是使用菜單。提供各種選項可以幫助腳本用戶了解腳本能做什么和不能做什么。通常菜單腳本會清空顯示區域,然后顯示可用的選項列表。用戶可以按下與每個選項關聯的字母或數字來選擇選項。shell腳本菜單的核心是case命令。 case命令會根據用戶在菜單上的選擇來執行特定命令。
9.1.1 創建菜單布局
創建菜單的第一步顯然是決定在菜單上顯示哪些元素以及想要顯示的布局方式。在創建菜單前,通常要先清空顯示器上已有的內容。這樣就能在干凈的、沒有干擾的環境中顯示菜單了。clear命令用當前終端會話的terminfo數據來清理出現在屏幕上的文本。運行clear命令之后,可以用echo命令來顯示菜單元素。默認情況下, echo命令只顯示可打印文本字符。在創建菜單項時,非可打印字符通常也很有用,比如制表符和換行符。要在echo命令中包含這些字符,必須用-e選項。因此,命令如下:
[root@kittod ~]# echo -e "1.\tDisplay disk space"
1. Display disk space
這極大地方便了菜單項布局的格式化。只需要幾個echo命令,就能創建一個看上去還行的菜單。
[root@kittod ~]# cat menu01.sh
#!/bin/bashclear
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選項來限制只讀取一個字符。這樣用戶只需要輸入一個數字,也不用按回車鍵:
[root@kittod ~]# cat menu01.sh
#!/bin/bashclear
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: "
read -n 1 option[root@kittod ~]# bash menu01.shSys Admin Menu1. Display disk space2. Display logged on users3. Display memory usage0. Exit menuEnter option:
接下來,你需要創建自己的菜單函數。
9.1.2 創建菜單函數
shell腳本菜單選項作為一組獨立的函數實現起來更為容易。這樣你就能創建出簡潔、準確、容易理解的case命令。
要做到這一點,你要為每個菜單選項創建獨立的shell函數。創建shell菜單腳本的第一步是決定你希望腳本執行哪些功能,然后將這些功能以函數的形式放在代碼中。
[root@kittod ~]# cat menu02.sh
#!/bin.bash function menu {clearecho 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:"read -n 1 option
}
menu
這樣一來,任何時候你都能調用menu函數來重現菜單。
9.1.3 添加菜單邏輯
現在你已經建好了菜單布局和函數,只需要創建程序邏輯將二者結合起來就行了。前面提到過,這需要用到case命令。case命令應該根據菜單中輸入的字符來調用相應的函數。用默認的case命令字符(星號)來處理所有不正確的菜單項是種不錯的做法。
下面的代碼展示了典型菜單中case命令的用法。
menu
case $option in
0)break ;;
1)diskspace ;;
2)whoseon ;;
3)memusage ;;
*)clearecho "Sorry, wrong selection" ;;
esac
這段代碼首先用menu函數清空屏幕并顯示菜單。 menu函數中的read命令會一直等待,直到用戶在鍵盤上鍵入了字符。然后, case命令就會接管余下的處理過程。 case命令會基于返回的字符調用相應的函數。在函數運行結束后, case命令退出。
9.1.4 整合 shell 腳本菜單
現在已經看到了構成shell腳本菜單的各個部分,讓我們將它們組合在一起,看看彼此之間是如何協作的。這里是一個完整的菜單腳本的例子。
[root@kittod ~]# cat menu03.sh
#!/bin.bash function diskspace {cleardf -k
}
function whoseon {clearwho
}
function memusage {clearcat /proc/meminfo
}
function menu {clearecho 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:"read -n 1 option
}
while [ 1 ]
domenucase $option in0)break ;;1)diskspace ;;2)whoseon ;;3)memusage ;;*)clearecho "Sorry,wrong selection" ;;esacecho -en "\n\n\t\t\tHit ant key to continue"read -n 1 line
done
clear
這個菜單創建了三個函數,利用常見的命令提取Linux系統的管理信息。它使用while循環來一直菜單,除非用戶選擇了選項0,這時,它會用break命令來跳出while循環。可以用這個模板創建任何shell腳本菜單界面。它提供了一種跟用戶交互的簡單途徑。
9.1.5 使用 select 命令
創建文本菜單的一半工夫都花在了建立菜單布局和獲取用戶輸入。 bashshell提供了一個很容易上手的小工具,幫助我們自動完成這些工作。
select命令只需要一條命令就可以創建出菜單,然后獲取輸入的答案并自動處理。 select命令的格式如下
select variable in list
docommands
done
list參數是由空格分隔的文本選項列表,這些列表構成了整個菜單。 select命令會將每個列表項顯示成一個帶編號的選項,然后為選項顯示一個由PS3環境變量定義的特殊提示符。
注意:PS1變量補充
[root@kittod ~]# echo $PS1
[\u@\h \W]\$
PS1的常用參數以及含義:\d :代表日期,格式為weekday month date,例如:"Mon Aug 1"\H :完整的主機名稱\h :僅取主機名中的第一個名字\t :顯示時間為24小時格式,如:HH:MM:SS\T :顯示時間為12小時格式\A :顯示時間為24小時格式:HH:MM\u :當前用戶的賬號名稱\v :BASH的版本信息\w :完整的工作目錄名稱\W :利用basename取得工作目錄名稱,只顯示最后一個目錄名\# :下達的第幾個命令\$ :提示字符,如果是root用戶,提示符為 # ,普通用戶則為 $顏色設置參數在PS1中設置字符顏色的格式為:\[\e[F;Bm\]........\[\e[0m\],其中“F“為字體
顏色,編號為30-37,“B”為背景顏色,編號為40-47,\[\e[0m\]作為顏色設定的結束。顏色對照表:F B30 40 黑色31 41 紅色32 42 綠色33 43 黃色34 44 藍色35 45 紫紅色36 46 青藍色37 47 白色只需將對應數字套入設置格式中即可。比如要設置命令行的格式為綠字黑底(\[\e[32;40m\]),顯示當前用戶的賬號名稱
(\u)、主機的第一個名字(\h)、完整的當前工作目錄名稱(\w)、24小時格式時間(\t),可以
直接在命令行鍵入如下命令:
# PS1='[\[\e[32;40m\]\u@\h \w \t]$ \[\e[0m\]'
也可以嘗試:
# PS1="\[\e[37;40m\][\[\e[32;40m\]\u\[\e[37;40m\]@\h \[\e[36;40m\]\w\
[\e[0m\]]\\$ "如果需要永久保存,保存到用戶變量文件中。
注意:PS2變量補充
一個非常長的命令可以通過在末尾加 \ 使其分行顯示
PS2多行命令的默認提示符,默認值是 >
[root@kittod ~]# echo \
> ^C
[root@kittod ~]# PS2=">+ "
[root@kittod ~]# echo \
>+
注意:PS3變量補充
你可以像下面示范的那樣,用環境變量PS3定制shell腳本的select提示:
沒有PS3提示符時候的情況:
[root@kittod ~]# cat ps3.sh
select i in mon tue wed exit
docase $i inmon) echo "Monday";;tue) echo "Tuesday";;wed) echo "Wednesday";;exit) exit;;esacdone
[root@kittod ~]# bash ps3.sh
1) mon
2) tue
3) wed
4) exit
#? 1
Monday
#? 2
Tuesday
#? 3
Wednesday
#? 4
有PS3提示符的時候的情況:
[root@kittod ~]# cat ps301.sh
PS3="Select a day (1-4): "
select i in mon tue wed exit
docase $i inmon) echo "Monday";;tue) echo "Tuesday";;wed) echo "Wednesday";;exit) exit;;esac
done[root@kittod ~]# bash ps301.sh
1) mon
2) tue
3) wed
4) exit
Select a day (1-4): 1
Monday
Select a day (1-4): 2
Tuesday
Select a day (1-4): 3
Wednesday
Select a day (1-4): 4
這里有一個select命令的簡單示例。
[root@kittod ~]# cat menu04.sh
#!/bin/bash
function diskspace {cleardf -k
}
function whoseon {clearwho
}
function memusage {clearcat /proc/meminfo
}
PS3="Enter option: "
select option in "Display disk space" "Display logged on users" "Display memory usage" "Exit program"
docase $option in"Exit program")break ;;"Display disk space")diskspace ;;"Display logged on users")whoseon ;;"Display memory usage")memusage ;;*)clearecho "Sorry, wrong selection" ;;esac
done
clear
select語句中的所有內容必須作為一行出現。這可以從行接續字符中看出。運行這個程序時, 它會自動生成如下菜單。
[root@kittod ~]# bash menu04.sh
1) Display disk space 3) Display memory usage
2) Display logged on users 4) Exit program
Enter option: 1
...
在使用select命令時,記住,存儲在變量中的結果值是整個文本字符串而不是跟菜單選項相關聯的數字。文本字符串值才是你要在case語句中進行比較的內容。
9.2 創建文本圖形腳本
使用文本菜單沒錯,但在我們的交互腳本中仍然欠缺很多東西,尤其是相比圖形化窗口而言。dialog包最早是由Savio Lam創建的一個小巧的工具,現在由Thomas E. Dickey維護。該包能夠用ANSI轉義控制字符在文本環境中創建標準的窗口對話框。你可以輕而易舉地將這些對話框融入自己的shell腳本中,借此與用戶進行交互。
檢查系統是否安裝,如果沒有安裝則進行安裝:
[root@kittod ~]# dnf install dialog
9.2.1 dialog軟件包
dialog命令使用命令行參數來決定生成哪種窗口部件( widget)。部件是dialog包中窗口元素類型的術語。
dialog包現在支持下表中的部件類型:
正如在表中看到的,我們可以選擇很多不同的部件。只用多花一點工夫,就可以讓腳本看起來更專業。
要在命令行上指定某個特定的部件,需使用雙破折線格式。
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文件中。
[root@kittod ~]# cat age.txt
20[root@kittod ~]#
9.2.2 部件演示
1、消息框
[root@kittod ~]# dialog --title "Testing" --msgbox "This is a test" 10 20
2、yesno 框
[root@kittod ~]# dialog --title "Yes/No" --no-shadow --yesno "Delete the file /tmp/test.txt?" 10 20
3、輸入框
[root@kittod ~]# dialog --title "Input your name" --inputbox "Please input your name:" 10 20 2>/tmp/name.txt
[root@kittod ~]# cat /tmp/name.txt
hehe[root@kittod ~]#
4、密碼框
[root@kittod ~]# dialog --title "Password" --passwordbox "Please give a password for the new user: " 10 20
這樣我們的密碼就暴露出來了,不是很不安全,所以通常我們會加上一個安全選項,-- insecure 將每個字符用 * 來顯示出來
5、文本框
[root@kittod ~]# dialog --title "The fstab" --textbox /etc/fstab 10 40
6、菜單框
[root@kittod ~]# dialog --title "Pick a choice" --menu "Choose one" 12 35 5 1 "say hello to everyone" 2 "thanks for your support" 3 "exit"
7、文本選擇框
[root@kittod ~]# dialog --title "Pick a choice" --fselect /root/ 7 40
8、復選框
格式:
dialog --checklist "Test" height width menu-height tag1 item1 tag2
item2 …[root@kittod ~]# dialog --backtitle "Checklist" --checklist "Test" 20 50 10 Memory Memory_Size 1 Disk Disk_size 2
9、顯示日歷
格式:
dialog --calendar "Date" height width day month year[root@kittod ~]# dialog --title "Calendar" --calendar "Date" 5 50
10、進度框架
dialog --gauge text height width [<percent>]
·固定進度顯示
[root@kittod ~]# dialog --title "installtion pro" --gauge "installtion" 10 30 10
·實時動態進度
[root@kittod ~]# for i in {1..100};do echo $i;done | dialog --title "installation pro" --gauge "installtion" 10 30
·編輯到腳本中
[root@kittod ~]# cat gauge01.sh
#!/bin/bash
declare -i PERCENT=0
(for I in /etc/*;doif [ $PERCENT -le 100 ]; thencp -r $I /tmp/test 2> /dev/nullecho "XXX"echo "Copy the file $I ..."echo "XXX"echo $PERCENTfilet PERCENT+=1sleep 0.1done
) | dialog --title "coping" --gauge "starting to copy files..." 6 50 0
11、表單框架
dialog --form text height width formheight [ label y x item y x flen ilen ] ...
其中,
·flen 表示 Field Length,定義了:選定字段中顯示的長度
·ilen 表示 Input Length,定義了:輸入的數據允許的長度
使用 Up/Down(或 Ctrl - N,Ctrl - P)在使用領域之間移動。使用 Tab 鍵在窗口之間切換。
[root@kittod ~]# dialog --title "Add a user" --form "please input the
information of new user: " 12 40 4 \
> "Username: " 1 1 "" 1 15 15 0 \
> "Fullname: " 2 1 "" 2 15 15 0 \
> "HomeDir: " 3 1 "" 3 15 15 0 \
> "Shell: " 4 1 "" 4 15 15 0
9.2.3 綜合應用實例
[root@kittod ~]# cat dia01.sh
#!/bin/bashyesno(){
dialog --title "First screen" --backtitle "Test Program" --clear --yesno \"Start this test program or not ? \nThis decesion have to make by you. " 16 51# yes is 0, no is 1 ,esc is 255result=$?if [ $result -eq 1 ]; thenexit 1;elif [ $result -eq 255 ]; thenexit 255;fiusername
}username(){cat /dev/null > /tmp/test.usernamedialog --title "Second screen" --backtitle "Test Program" --clear --inputbox \"Please input your username (default: hello) " 16 51 "hello" 2>/tmp/test.usernameresult=$?if [ $result -eq 1 ]; thenyesnoelif [ $result -eq 255 ]; thenexit 255;fipassword
}password(){cat /dev/null >/tmp/test.passworddialog --insecure --title "Third screen" --backtitle "Test Program" --clear --passwordbox "Please input your password (default: 12345) " 16 51 "12345" 2>/tmp/test.passwordresult=$?if [ $result -eq 1 ];thenusernameelif [ $result -eq 255 ]; thenexit 255;fioccupation
}occupation(){cat /dev/null > /tmp/test.occupationdialog --title "Forth screen" --backtitle "Test Program" --clear --menu \"Please choose your occupation: (default: IT)" 16 51 3 \IT "The worst occupation" \CEO "The best occupation" \Teacher "Not the best or worst" 2> /tmp/test.occupationresult=$?if [ $result -eq 1 ]; thenpasswordelif [ $result -eq 255 ]; thenexit 255;fifinish
}finish(){dialog --title "Fifth screen" --backtitle "Test Program" --clear --msgbox \"Congratulations! The test program has finished !\n Username:
$(cat /tmp/test.username)\n Password: $(cat /tmp/test.password)\n
Occupation: $(cat /tmp/test.occupation)" 16 51result=$?if [ $result -eq 1 ]; thenoccupationelif [ $result -eq 255 ]; thenexit 255;fi
}yesno
執行該腳本:
9.3 創建真正圖形的腳本
如果想給交互腳本加入更多的圖形元素,你可以再進一步。 KDE和GNOME桌面環境都擴展了dialog命令的思路,包含了可以在各自環境下生成X Window圖形化部件的命令。
KDE圖形化環境默認包含kdialog包。 kdialog包使用kdialog命令在KDE桌面上生成類似于dialog式部件的標準窗口。生成的窗口能跟其他KDE應用窗口很好地融合,不會造成不協調的感覺。這樣你就可以直接在shell腳本中創建能夠和Windows相媲美的用戶界面了。
GNOME圖形化環境支持兩種流行的可生成標準窗口的包:
·gdialog
·zenity
zenity是大多數GNOME桌面Linux發行版上最常見的包 這個包可以創建真正的基于圖形窗口的腳本。我們的操作系統在安裝時使用了GNOME圖形環境,而在默認環境里,系統已經安裝了zenity軟件包。所以我們可以使用該軟件來創建真正的圖形腳本。
9.3.1 基本命令
查看日歷
[root@kittod ~]# zenity --calendar 1
查看文件選擇
[root@kittod ~]# zenity --file-selection
9.3.2 綜合實例
[root@kittod ~]# cat zen01.sh
#!/bin/bashtemp=`mktemp -t temp.XXXXXX`
temp2=`mktemp -t temp.XXXXXX`function diskspace(){df -h > $tempzenity --text-info --title "Disk space" --filename=$temp --width 750 --height 10
}function whoseon(){who > $tempzenity --text-info --title "Logged in users" --filename=$temp --width 750 --height 10
}function memusage(){cat /proc/meminfo > $tempzenity --text-info --title "Memory usage" --filename=$temp --width 750 --height 10
}while [ 1 ]
dozenity --list --radiolist --title "Sys Admin Menu" --column "Select" --column "Menu Item" FALSE "Display disk space" FALSE "Display users" FALSE "Display memory usage" FALSE "Exit" > $temp2if [ $? -eq 1 ]then break;fiselection=$(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中使用選項的全文本。如果文本中有任何空格,你需要給文本加上引號。
使用zenity包,你可以給GNOME桌面上的交互式shell腳本帶來一種Windows式的體驗。