shell 編程 之 小技巧
1 概述
本文將通過介紹shell腳本編程過程中常用的一些命令,來提高shell腳本編程的靈活性,以及高效實現編程結果
分別介紹了以下10個工具
shift,select,信號捕捉,數組,字符串處理,定義變量,eval,間接變量引用,mktemp,install
2 shift 控制循環
shift [n]
n 用於將參量列表list 左移指定次數,缺省為左移一次。
參量列表list 一旦被移動,最左端的那個參數就從列表中刪除。while 循環遍歷位置參量列表時,常用到shift
運行 ./Tshift.sh a b c d 可以看到每次循環$1的值都不一樣,而且依次向左移動,參數的個數也不一樣
腳本如下:
until (($#==0));do echo "\$1 is $1" echo "var num \$# is $#" shift done
3 select循環與菜單
語法如下
select variable in list
do
循環體命令
done
select 循環主要用於創建菜單,按數字順序排列的菜單項將顯示在標準錯誤上,並顯示PS3 提示符,等待用戶輸入
用戶輸入菜單列表中的某個數字,執行相應的命令
用戶輸入被保存在內置變量REPLY 中
select 是個無限循環,因此要記住用break 命令退出循環,或用exit 命令終止腳本。也可以按ctrl+c 退出循環
select 經常和case 聯合使用
與for 循環類似,可以省略in list,此時使用位置參量
腳本如下
註意,如果把註釋的#select menu in [email protected]這句話啟用,就註釋掉菜單那一句,並且執行的時候,要帶上參數。
PS3="please input your choice: " select menu in well job hello world bye; #select menu in [email protected]; do case $menu in well) echo "You have done well" ;; job) echo "Nice job" ;; hello) echo "hello world" ;; world) echo "work hard" ;; bye) echo "See U tomorrow" break ;; *) echo "Please re-input" ;; esac done
4 信號捕捉
trap ‘觸發指令‘ 信號:自定義進程收到系統發出的指定信號後,將執行觸發指令,而不會執行原操作
trap ‘‘ 信號:忽略信號的操作
trap ‘-‘ 信號:恢復原信號的操作
trap -p:列出自定義信號操作
通過執行以下的腳本可以看出效果,ctrl + c 操作時sigint信號
SIGKILL 這個信號不能被捕捉,即-9捕捉不了
測試
當第一個循環的時候,執行kill -2 pid,此時是2信號被忽略,按ctrl+c,腳本不會結束
進入第二個循環前,已經恢復了2的默認信號
在第二個循環的時候,按ctrl+c,腳本結束運行,退出狀態碼是130.被中斷退出。
在第三個循環的時候,自定義了2信號,按ctl+c 或者執行kill -2 pid會打印now catch int 2這句話,同時退出狀態碼是88
trap ‘‘ int echo "pid is $$" echo "now 1 diy trap signal" trap -p i=1 while [ $i -lt 5 ] do sleep 5 echo now i is $i let i++ done trap ‘-‘ int echo "now 2 diy trap signal" trap -p j=1 while [ $j -lt 5 ];do echo j is $j let j++ sleep 2 done trap "echo now catch int 2;exit 88" 2 echo "now 3 diy trap signal" trap -p m=1 while [ $m -lt 5 ];do echo m is $m let m++ sleep 3 done echo now $0 done
5 數組
數組可以理解成多個變量的集合,當定義的變量含有多個元素,建議用數組,比較方便
變量:存儲單個元素的內存空間
數組:存儲多個元素的連續的內存空間,相當於多個變量的集合
數組名和索引
索引:編號從0開始,屬於數值索引
註意:索引可支持使用自定義的格式,而不僅是數值格式,即為關聯索引,bash4.0版本之後開始支持
bash的數組支持稀疏格式(索引不連續)
聲明數組:
declare -a ARRAY_NAME
declare -A ARRAY_NAME
-a定義的是普通的數值,也叫下標數組,下標數組元素是通過數組下標(數組下標可以是算術表達式,其結果必須是一個整數)來訪問的,但是這種訪問方式在表達某些關聯性很強的數據時會存在限制。
-A定義的是關聯數組,使用任意的字符串作為下標(不必是整數)來訪問數組元素,關聯數組的下標和值稱為鍵值對,它們是一一對應的關系。在關聯數組中,鍵是唯一的,值可以不唯一。
shell 的關聯數組和 shell 的下標數組在定義和使用上完全一樣,只是在索引上有區別。
註意:兩者不可相互轉換,在使用關聯數組之前,需要使用命令 declare -A array 進行顯示聲明。默認數組定義是-a
5.1 數組賦值
數組元素的賦值
註意,如果定義重復名稱的數組,則原來數值的所有值都會被覆蓋
只有一次只賦值一個元素,這個定義方式不會覆蓋掉整個數組,其他三個方式都會覆蓋所有的數組
(1) 一次只賦值一個元素,這個定義方式不會覆蓋掉整個數組
ARRAY_NAME[INDEX]=VALUE
weekdays[0]="Sunday"
weekdays[4]="Thursday"
(2) 一次賦值全部元素
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
(3) 只賦值特定元素
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) 交互式數組值對賦值
read -a ARRAY,然後輸入參數,用空格隔開,數組定義完成後按enter結束對ARRAY數組的定義
5.2 引用數組
引用數組元素:
${ARRAY_NAME[INDEX]}
註意:省略[INDEX]表示引用下標為0的元素
引用數組所有元素:
${ARRAY_NAME[*]}
${ARRAY_NAME[@]}
數組的長度(數組中元素的個數):
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
刪除數組中的某元素:導致稀疏格式
unset ARRAY[INDEX]
如unset sunny[2]
刪除整個數組:
unset ARRAY
查看所有數組
顯示所有普通數組:declare -a
顯示所有關聯數組:declare -A
5.3數組數據處理
引用數組中的元素:
數組切片:${ARRAY[@]:offset:number}
offset: 要跳過的元素個數
number: 要取出的元素個數
如: declare -a weekday=‘([0]="Sun" [1]="Mon" [2]="Tue" [3]="Wen" [4]="Thu")‘
echo $[weekday[@]:2:2]
結果是Tue Wen
取偏移量之後的所有元素${ARRAY[@]:offset}
向數組中追加元素:
ARRAY[${#ARRAY[*]}]=value
關聯數組:
declare -A ARRAY_NAME ARRAY_NAME=([idx_name1]=‘val1‘ [idx_name2]=‘val2‘...)
5.4 例子
以下兩個例子
ex1 找出10個99以內的隨機數的最大值和最小值
ex2 計算/var/log/*.log下所有下標是偶數的文件的行數的總和
註意ex2 中
files=(/var/log/*.log)
直接給數組分配了值,用來通配符的寫法
#ex1: to find max and min num in ten nums declare -a rand declare -i max=0 declare -i min=32767 for i in {0..9} ; do rand[$i]=$[$RANDOM%99] echo rand[$i]=${rand[$i]} [ ${rand[$i]} -gt $max ] && max=${rand[$i]} [ ${rand[$i]} -lt $min ] && min=${rand[$i]} done echo "MAX:$max min:$min" #ex2:to sum the lines in /var/log/*.log which subscript is even num declare -a files files=(/var/log/*.log) declare -i lines=0 for i in $(seq 0 $[${#files[*]}-1]);do if [ $[$i%2] -eq 0 ];then let lines+=$(wc -l ${files[$i]} | cut -d " " -f1) fi done echo "total lines is $lines"
6 字符串處理
6.1 字符串切片
${var:offset}:返回字符串變量var中從第offset個字符後(不包括第offset個字符)的字符開始,到最後的部分,offset的取值在0 到${#var}-1 之間(bash4.2後,允許為負值)
${var:offset:number}:返回字符串變量var中從第offset個字符後(不包括第offset個字符)的字符開始,長度為number的部分
${var: -length}:取字符串的最右側幾個字符,相當於取最右邊
註意:冒號後必須有一空白字符
${var:offset:-length}:從最左側跳過offset字符,一直向右取到距離最右側lengh個字符之前的內容,相當於取中間
${var: -length:-offset}:先從最右側向左取到length個字符開始,再向右取到距離最右側offset個字符之間的內容,先截斷一部分,再取截斷後的前面部分
註意:-length前空格
6.2基於模式取子串
${var#*word}:其中word可以是指定的任意字符
功能:自左而右,查找var變量所存儲的字符串中,第一次出現的word, 刪除字符串開頭至第一次出現word字符之間的所有字符
${var##*word}:同上,貪婪模式,不同的是,刪除的是字符串開頭至最後一次由word指定的字符之間的所有內容
示例:
file="var/log/messages“
${file#*/}: log/messages
${file##*/}: messages
${var%word*}:其中word可以是指定的任意字符;
功能:自右而左,查找var變量所存儲的字符串中,第一次出現的word, 刪除字符串最後一個字符向左至第一次出現word字符之間的所有字符;
file="/var/log/messages"
${file%/*}: /var/log
${var%%word*}:同上,只不過刪除字符串最右側的字符向左至最後一次出現word字符之間的所有字符;
示例:
url=http://www.magedu.com:80
${url##*:}80
${url%%:*}http
6.3查找替換
${var/pattern/substr}:查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替換之
${var//pattern/substr}: 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替換之
${var/#pattern/substr}:查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替換之
${var/%pattern/substr}:查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替換之
6.4查找並刪除
${var/pattern}:刪除var所表示的字符串中第一次被pattern所匹配到的字符串
${var//pattern}:刪除var所表示的字符串中所有被pattern所匹配到的字符串
${var/#pattern}:刪除var所表示的字符串中所有以pattern為行首所匹配到的字符串
${var/%pattern}:刪除var所表示的字符串中所有以pattern為行尾所匹配到的字符串
6.5字符大小寫轉換
${var^^}:把var中的所有小寫字母轉換為大寫
${var,,}:把var中的所有大寫字母轉換為小寫
6.6變量賦值
變量賦值還有以下的寫法
以- 減號為標準來看
-當舊變量沒有賦值時,新變量為賦值的值
-當舊變量已經有賦值了,新變量就和就變量一樣,包括舊變量賦值為空字符串
:-區別就在舊變量為空字符串,新的變量就是賦值的值
其他一樣
以- 減號為標準來看
多了:冒號一般就是強制的賦值,作用於當舊變量已經賦予空字符串的時候
-當舊變量沒有賦值時,新變量為賦值的值
-當舊變量已經有賦值了,新變量就和就變量一樣,包括舊變量賦值為空字符串
:-區別就在舊變量為空字符串,新的變量就是賦值的值
其他一樣
+加號特殊,剛好和-減號大概相反的功能
等號和減號差不多,但是,等號會把舊的變量在沒有設定的情況下,會把舊的變量也一起賦值,同時,當舊變量是空字符的時候,新變量也是空字符,等號就是,當舊變量沒賦值時,新變量為賦值的字段,當舊變量由賦值,等號就是新變量
:=就是舊變量沒有賦值時或者空字符時,新舊變量都是賦值的值,但是舊變量由賦值,新變量為舊變量的值。舊變量不變
?比較特殊,會檢測舊變量是否存在,舊變量沒有賦值,即不存在,就輸出錯,舊變量已經有賦值,新變量就是舊變量的值,舊變量不變,
:?多了冒號,就是當舊變量也為空字符,也輸出錯誤
7 定義變量類型
Shell變量一般是無類型的,但是bash Shell提供了declare和typeset兩個命令用於指定變量的類型,兩個命令是等價的
declare [選項] 變量名
-r 聲明或顯示只讀變量
一旦被賦值為只讀的變量,那麽這個變量將不再被重新賦值或者聲明,也不能被取消設置,必須退出當前shell重新登錄才能取消變量的賦值或定義
-i將變量定義為整型數
-a 將變量定義為數組
-A 將變量定義為關聯數組,下標可以不是數字
-f 顯示已定義的所有函數名及其內容
-F 僅顯示已定義的所有函數名
-x 聲明或顯示環境變量和函數
-l 聲明變量為小寫字母declare –l var=lower
這裏會將var這個變量中原來是大寫的字母全部轉換成小寫字母,小寫字母不變,var實際被賦予的值不包含大寫字母
-u 聲明變量為大寫字母declare –u var=UPPER
這裏會將var這個變量中原來是小寫的字母全部轉換成大寫字母,大寫字母不變,var實際被賦予的值不包含小寫字母
8 eval命令
eval命令將會首先掃描命令行進行所有的置換,然後再執行該命令。該命令適用於那些一次掃描無法實現其功能的變量.該命令對變量進行兩次掃描
示例:
[[email protected]~]# CMD=whoami [[email protected] ~]# echo $CMD whoami [[email protected] ~]# eval $CMD root [[email protected]~]# n=10 [[email protected]~]# echo {0..$n} {0..10} [[email protected]~]# eval echo {0..$n} 0 1 2 3 4 5 6 7 8 9 10
9 間接變量引用
如果第一個變量的值是第二個變量的名字,從第一個變量引用第二個變量的值就稱為間接變量引用
variable1的值是variable2,而variable2又是變量名,variable2的值為value,間接變量引用是指通過variable1獲得變量值value的行為
variable1=variable2 variable2=value tempvar=$variable1
此時tempvar這個變量的值是variable2,但是要實現間接引用,使得tempvar的值通過variable1可以被賦值value,就是所謂的間接引用
bash Shell提供了兩種格式實現間接變量引用
花括號裏不能有$號,如果要引用花括號裏的變量,就要用!感嘆號
eval tempvar=\$$variable1 tempvar=${!variable1}
示例:
[[email protected] ~]# N=NAME [[email protected] ~]# NAME=sunny [[email protected] ~]# N1=${!N} [[email protected] ~]# echo $N1 sunny [[email protected] ~]# eval N2=\$$N [[email protected] ~]# echo $N2 sunny
10 創建臨時文件
mktemp命令:創建並顯示臨時文件,可避免沖突
mktemp[OPTION]... [TEMPLATE]
TEMPLATE: filename.XXX
X至少要出現三個,為大寫的字母X
OPTION:
-d: 創建臨時目錄
-p DIR或--tmpdir=DIR:指明臨時文件所存放目錄位置
示例:
mktemp/tmp/test.XXX
tmpdir=`mktemp –d /tmp/testdir.XXX`
創建一個臨時目錄,同時把這個目錄的名稱賦值給tmpdir這個變量
mktemp --tmpdir=/testdir test.XXXXXX
11 安裝復制文件
install命令的作用是安裝或升級軟件或備份數據,它的使用權限是所有用戶。
install命令和cp命令類似,都可以將文件/目錄拷貝到指定的地點。但是,install允許你控制目標文件的屬性。
install在拷貝的同時制定新生成文件的屬性,如制定rwx或者所屬組或者所有者的屬性
install通常用於程序的makefile,使用它來將程序拷貝到目標(安裝)目錄。
install命令:
install [OPTION]... [-T] SOURCE DEST 單文件
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -t DIRECTORY SOURCE...
install [OPTION]... -d DIRECTORY...創建空目錄
選項:
-m MODE,默認755
-o OWNER
-g GROUP
-d 創建新的目錄
更多選項查看鏈接:http://man.linuxde.net/install
示例:
install -m 700 -o wang -g admins srcfile desfile install –m 766 –d /testdir/installdir
12 總結
編寫腳本的時候,可以借助以上10個工具在來提高編程的效率。
本文出自 “自學linux” 博客,請務必保留此出處http://ghbsunny.blog.51cto.com/7759574/1962589
shell 編程 之 小技巧