內部變數的學習 內建變數,這些變數將會影響bash指令碼的行為.$BASH Bash的二進位程式檔案的路徑root@ubuntu:~/resource/shell-study/0506-2013# echo $BASH /bin/bash $BASH_ENV這個環境變數會指向一個Bash的開機檔案, 當一個指令碼被調用的時候, 這個開機檔案將會被讀取. $BASH_SUBSHELL這個變數用來提示子shell的層次. 這是一個Bash的新特性, 直到版本3的Bash才被引入近來. $BASH_VERSINFO[n]這是一個含有6個元素的數組, 它包含了所安裝的Bash的版本資訊. 這與下邊的$BASH_VERSION很相像, 但是這個更加詳細一些.root@ubuntu:~/resource/shell-study/0506-2013# for n in 0 1 2 3 4 5 > do > echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}" > done BASH_VERSINFO[0] = 4 BASH_VERSINFO[1] = 1 BASH_VERSINFO[2] = 5 BASH_VERSINFO[3] = 1 BASH_VERSINFO[4] = release BASH_VERSINFO[5] = i486-pc-linux-gnu $BASH_VERSION安裝在系統上的Bash版本號碼root@ubuntu:~/resource/shell-study/0506-2013# echo $BASH_VERSION 4.1.5(1)-release 這個輸出的資訊和上面通過數組查詢到的資訊是一一對應的$DIRSTACK在目錄棧中最頂端的值. (將會受到pushd和popd的影響),這個內建變數與dirs命令相符, 但是dirs命令會顯示目錄棧的整個內容. $EDITOR指令碼所調用的預設編輯器, 通常情況下是vi或者是emacs. $EUID"有效"使用者ID,不管目前使用者被假定成什麼使用者, 這個數都用來表示目前使用者的標識號, 也可能使用su命令來達到假定的目的.,$EUID並不一定與$UID相同. $FUNCNAME(當前函數的名字)#!/bin/bash func () { echo "$FUNCNAME is running." } func echo "FUNCNAME = $FUNCNAME" exit 0 結果:root@ubuntu:~/resource/shell-study/0506-2013# ./test7.sh func is running. FUNCNAME = root@ubuntu:~/resource/shell-study/0506-2013# 第二行沒有name,因為FUNCNAME只能用在函數方法內部使用$GLOBIGNORE一個檔案名稱的模式比對列表, 如果在通配(globbing)中匹配到的檔案包含有這個列表中的某個檔案, 那麼這個檔案將被從匹配到的結果中去掉. $GROUPS目前使用者所屬的組,這是一個目前使用者的組id列表(數組), 與記錄在/etc/passwd檔案中的內容一樣 $HOME使用者的home目錄, 一般是/home/usernam $HOSTNAMEhostname放在一個初始化指令碼中, 在系統啟動的時候分配一個系統名字. 然而, gethostname()函數可以用來設定這個Bash內部變數$HOSTNAME $HOSTTYPE主控件類型,就像$MACHTYPE, 用來識別系統硬體. root@ubuntu:~/resource/shell-study/0506-2013# echo $HOSTNAME ubuntu root@ubuntu:~/resource/shell-study/0506-2013# echo $HOSTTYPE i486 root@ubuntu:~/resource/shell-study/0506-2013# echo $HOME /root root@ubuntu:~/resource/shell-study/0506-2013# echo $GROUPS 0 root@ubuntu:~/resource/shell-study/0506-2013# $IFS內部域分隔字元,這個變數用來決定Bash在解釋字串時如何識別域, 或者單詞邊界.$IFS預設為空白(空格, 定位字元,和分行符號), 但這是可以修改的, 比如, 在分析逗號分隔的資料檔案時, 就可以設定為逗號. 注意$*使用的是儲存在$IFS中的第一個字元#!/bin/bash output_args_one_per_line() { for arg do echo "[$arg]" done } echo "IFS=\" \"" IFS=" " var=" a b c " output_args_one_per_line $var echo "----------------" echo "IFS=:" IFS=":" var=":a::b:c:::" output_args_one_per_line $var exit 0 結果:root@ubuntu:~/resource/shell-study/0506-2013# ./test8.sh IFS=" " [a] [b] [c] ---------------- IFS=: [] [a] [] [b] [c] [] [] root@ubuntu:~/resource/shell-study/0506-2013# 可以看出還是挺奇怪的,當使用IFS=" "和使用“:”時,結果還是有些出入的,同樣的事情也會發生在awk的"FS"域中.$IGNOREEOF忽略EOF: 告訴shell在log out之前要忽略多少檔案結束符(control-D). $LC_COLLATE常在.bashrc或/etc/profile中設定, 這個變數用來控制檔案名稱擴充和模式比對的展開順序. 如果$LC_COLLATE設定得不正確的話, LC_COLLATE會在檔案名稱匹配(filename globbing)中產生不可預料的結果. $LC_CTYPE這個內部變數用來控制通配(globbing)和模式比對中的字串解釋. $LINENO這個變數用來記錄自身在指令碼中所在的行號. 這個變數只有在指令碼使用這個變數的時候才有意義, 並且這個變數一般用於調試目的. $MACHTYPE機器類型,標識系統的硬體. $OLDPWD之前的工作目錄("OLD-print-working-directory", 就是之前你所在的目錄) $OSTYPE作業系統類型 $PATH可執行檔的搜尋路徑, 一般為/usr/bin/, /usr/X11R6/bin/, /usr/local/bin, 等等. $PPID進程的$PPID就是這個進程的父進程的進程ID(pid). [1] $PROMPT_COMMAND這個變數儲存了在主提示符$PS1顯示之前需要執行的命令. $PS1這是主提示符, 可以在命令列中見到它. $PS2第二提示符, 當你需要額外輸入的時候, 你就會看到它. 預設顯示">". $PS3第三提示符, 它在一個select迴圈中顯示(參見例子 10-29). $PS4第四提示符, 當你使用-x選項來呼叫指令碼時, 這個提示符會出現在每行輸出的開頭. 預設顯示"+". $PWD工作目錄(你當前所在的目錄),這與內建命令pwd作用相同. $REPLY當沒有參數變數提供給read命令的時候, 這個變數會作為預設變數提供給read命令. 也可以用於select菜單, 但是只提供所選擇變數的編號, 而不是變數本身的值#!/bin/bash # REPLY是提供給'read'命令的預設變數. echo -n "What is your favorite vegetable? " read echo "Your favorite vegetable is $REPLY." # 若且唯若沒有變數提供給"read"命令時, REPLY才儲存最後一個"read"命令讀入的值. echo -n "What is your favorite fruit? " read fruit echo "Your favorite fruit is $fruit." echo "but...Value of \$REPLY is still $REPLY." # $REPLY還是儲存著上一個read命令的值, #+ 因為變數$fruit被傳入到了這個新的"read"命令中. exit 0 結果:root@ubuntu:~/resource/shell-study/0506-2013# ./test9.sh What is your favorite vegetable? Your favorite vegetable is . What is your favorite fruit? apple Your favorite fruit is apple. but...Value of $REPLY is still . root@ubuntu:~/resource/shell-study/0506-2013# $SECONDS這個指令碼已經啟動並執行時間(以秒為單位).#!/bin/bash TIME_LIMIT=10 INTERVAL=1 echo "Hit Control-C to exit before $TIME_LIMIT seconds." while [ "$SECONDS" -le "$TIME_LIMIT" ] do if [ "$SECONDS" -eq 1 ];then units=second else units=seconds fi echo "This script has been running $SECONDS $units." # 在一台比較慢或者是附載過大的機器上,在單次迴圈中, 指令碼可能會忽略計數. sleep $INTERVAL done echo -e "\a" # Beep!(嗶嗶聲!) exit 0 結果:root@ubuntu:~/resource/shell-study/0506-2013# ./test10.sh Hit Control-C to exit before 10 seconds. This script has been running 0 seconds. This script has been running 1 second. This script has been running 2 seconds. This script has been running 3 seconds. This script has been running 4 seconds. This script has been running 5 seconds. This script has been running 6 seconds. This script has been running 7 seconds. This script has been running 8 seconds. This script has been running 9 seconds. This script has been running 10 seconds. root@ubuntu:~/resource/shell-study/0506-2013# $SHELLOPTSshell中已經啟用的選項的列表, 這是一個唯讀變數.bash$ echo $SHELLOPTSbraceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs $SHLVLShell層級, 就是Bash被嵌套的深度. 如果是在命令列中, 那麼$SHLVL為1, 如果在指令碼中那麼$SHLVL為2. $TMOUT如果$TMOUT環境變數被設定為非零值time的話, 那麼經過time秒後, shell提示符將會逾時. 這將會導致登出(logout).#!/bin/bash #TMOUT=3 TIMELIMIT=5 PrintAnswer() { if [ "$answer" = TIMEOUT ];then echo $answer else echo "Your favorite veggie is $answer" kill $! fi } TimerOn() { sleep $TIMELIMIT && kill -s 14 $$ & } Int14Vector() { answer="TIMEOUT" PrintAnswer exit 14 } trap Int14Vector 14 echo "What is your favorite vegetable" TimerOn read answer PrintAnswer exit 0 結果:root@ubuntu:~/resource/shell-study/0506-2013# ./test11.sh What is your favorite vegetable TIMEOUT root@ubuntu:~/resource/shell-study/0506-2013# ./test11.sh What is your favorite vegetable all Your favorite veggie is all root@ubuntu:~/resource/shell-study/0506-2013# ^C $UID使用者ID號,目前使用者的使用者標識號, 記錄在/etc/passwd檔案中,這是目前使用者的真實id, 即使只是通過使用su命令來臨時改變為另一個使用者標識, 這個id也不會被改變. $UID是一個唯讀變數, 不能在命令列或者指令碼中修改它, 並且和id內建命令很相像.#!/bin/bash ROOT_UID=0 if [ "$UID" -eq "$ROOT_UID" ];then echo "You are root." else echo "You are just an ordinary user." fi ROOTUSER_NAME=root username=`whoami` #username=`id -nu` if [ "$username" = "$ROOTUSER_NAME" ];then echo "You are root." else echo "You are just an ordinary user." fi exit 0 結果:root@ubuntu:~/resource/shell-study/0507-2013# chmod +x test1.sh root@ubuntu:~/resource/shell-study/0507-2013# ./test1.sh You are root. You are root. 位置參數$0, $1, $2, 等等 位置參數, 從命令列傳遞到指令碼, 或者傳遞給函數, 或者set給變數 $#命令列參數或者位置參數的個數$*所有的位置參數都被看作為一個單詞,"$*"必須被引用起來.$@與$*相同, 但是每個參數都是一個獨立的引用字串, 這就意味著, 參數是被完整傳遞的, 並沒有被解釋或擴充. 這也意味著, 參數列表中每個參數都被看作為單獨的單詞,當然, "$@"應該被引用起來.#!/bin/bash E_BADARGS=65 if [ ! -n "$1" ];then echo "usage: `basename $0` args1 args2 etc." exit $E_BADARGS fi index=1 echo "Listing args with \"\$*\"" for arg in "$*" do echo "arg#$index = $arg" let "index+=1" done echo "entire arg list seen as single word." index=1 echo "Listing args with \"\$@\"" for arg in "$@" do echo "arg #$index = $arg" let "index+=1" done echo "arg list seen as separate words." index=1 echo "Listing args with \$* (unquoted):" for arg in $* do echo "arg #$index = $arg" let "index+=1" done echo "Arg list seen as separate words." exit 0 結果:root@ubuntu:~/resource/shell-study/0507-2013# ./test2.sh 1 2 34 Listing args with "$*" arg#1 = 1 2 34 entire arg list seen as single word. Listing args with "$@" arg #1 = 1 arg #2 = 2 arg #3 = 34 arg list seen as separate words. Listing args with $* (unquoted): arg #1 = 1 arg #2 = 2 arg #3 = 34 Arg list seen as separate words. root@ubuntu:~/resource/shell-study/0507-2013# shift的用法說明: #!/bin/bash echo "$@" shift echo "$@" shift echo "$@" 結果;root@ubuntu:~/resource/shell-study/0507-2013# ./test3.sh 1 2 3 4 5 6 1 2 3 4 5 6 2 3 4 5 6 3 4 5 6 root@ubuntu:~/resource/shell-study/0507-2013# $-傳遞給指令碼的標記(使用set命令). 參見例子 11-15.這本來是ksh的結構, 後來被引進到Bash中, 但是不幸的是, 看起來它不能夠可靠的用在Bash指令碼中. 一種可能的用法是讓一個指令碼測試自身是不是可互動的.$!運行在背景最後一個作業的PID(進程ID)$_這個變數儲存之前執行的命令的最後一個參數的值.#!/bin/bash echo $_ # /bin/bash du >/dev/null # 這麼做命令列上將沒有輸出. echo $_ # du ls -al >/dev/null # 這麼做命令列上將沒有輸出. echo $_ # -al (這是最後的參數) : echo $_ 結果:root@ubuntu:~/resource/shell-study/0507-2013# ./test4.sh ./test4.sh du -al : root@ubuntu:~/resource/shell-study/0507-2013# $?命令, 函數, 或者是指令碼本身的退出狀態代碼#!/bin/bash echo $? cat file #wrong command echo $? echo "right command." echo $? exit 0 結果:root@ubuntu:~/resource/shell-study/0507-2013# ./test5.sh 0 cat: file: No such file or directory 1 right command. 0 root@ubuntu:~/resource/shell-study/0507-2013# $$指令碼自身的進程ID. $$變數在指令碼中經常用來構造"唯一的"臨時檔案名稱