一、認識shell
什么是shell?shell為單詞外殼的意思。那么這是誰的外殼?我們知道一個系統中實際工作的是那些硬件,cpu、內存、磁盤等。我們如何調用這些硬件為我們工作?實際上,硬件是由內核kernel控制的。我們可以通過kernel控制硬件,但我們不能直接和內核kernel交流。我們需要一個外殼,這個外殼就是shell來溝通kernel。何為shell腳本,其實不過是一堆命令寫在一個文件中,這個文件具有執行權限。
二、變量
什么是變量?變量是腳本編程中數據表現的一中方法,變量是系統為了保留數據項在內存空間中分配一個位置或者一組位置的標識或名字。bash變量是不區分類型的,本質上都是字符串。
2.1 特殊的變量類型
本地變量:只對當前的shell進程有效,對其它shell進程無效,包含當前shell進程的子進程
[leon@localhost ~]$ test=string #定義一個本地變量 [leon@localhost ~]$ echo $test string [leon@localhost ~]$ bash #打開一個子shell [leon@localhost ~]$ echo $test [leon@localhost ~]$ #為null值
環境變量:對當前shell進程和子進程有效,對其它shell無效
[leon@localhost ~]$ export test=string #定義一個環境變量 [leon@localhost ~]$ echo $test string [leon@localhost ~]$ bash [leon@localhost ~]$ echo $test string
局部變量:對shell腳本中某段代碼片段有效,通常用于函數本地,通常用local來定義
[leon@localhost tmp]$ cat test.sh #!/bin/bash #定義使用哪種shell解析腳本 # function test { #定義一個函數 local a=local #定義一個局部變量 echo $a } test && echo $a [leon@localhost tmp]$ ./test.sh local
位置變量:$0 $1 $2…$n
[leon@localhost tmp]$ sh test1.sh 1 [leon@localhost tmp]$ cat test1.sh #!/bin/bash # echo $0 echo $1 echo $2 [leon@localhost tmp]$ sh test1.sh string1 string2 string3 #傳遞位置參數 test1.sh string1 string2
常用的特殊變量:$? $@ $* $# $$
[leon@localhost tmp]$ cat test2.sh #!/bin/bash # echo $* echo $@ echo $# echo $? echo $$ [leon@localhost tmp]$ sh test2.sh string1 string2 string3 string4 string1 string2 string3 string4 string1 string2 string3 string4 4 0 1650
數組 :是特殊的變量,bash支持一維數組。數組由數組名+索引 組成。
如:a[1] a[2] a[3] … a[N] a[hello] a[Number] a[string] …
2.2 變量的聲明及賦值
1.不能使用系統內置變量
2.以字母,數字,下劃線組成,不能以數字開頭
3.見名知義
[leon@localhost tmp]$ PATH=/tmp [leon@localhost tmp]$ ls bash: ls: command not found [leon@localhost ~]$ [leon@localhost ~]$ 1test=test -bash: 1test=test: command not found
定義整型的變量
[leon@localhost ~]$ declare -i number=23 #使用declare -i定義一個整型變量
定義數組
可以使用declare 定義
[leon@localhost ~]$ declare -a a=(1 2 3 4) #定義一個數組 [leon@localhost ~]$ echo ${a[@]} 1 2 3 4 [leon@localhost ~]$ b=(1 2 3 4) [leon@localhost ~]$ echo ${b[@]} 1 2 3 4 [leon@localhost ~]$ declare -A string=([hello]='hello' [day]='sunday') #定義一個關聯型數組 [leon@localhost ~]$ echo ${string[@]} sunday hello [leon@localhost ~]$ logs=(/home/*) #給變量賦值 [leon@localhost ~]$ echo ${logs[@]} /home/leon /home/openstack /home/test
三、數組及字符串操作
3.1 數組操作
3.1.1 數組長度
${#ARRAY[*]}
${#ARRAY[@]}
[leon@localhost ~]$ declare -A string=([hello]='hello' [day]='sunday') [leon@localhost ~]$ echo ${#string[@]} && echo ${#string[*]} 2 2
3.1.2 數組中挑選某些元素
${ARRAY[@]:offset:number}
[leon@localhost ~]$ echo ${string[@]} sunday hello [leon@localhost ~]$ echo ${string[@]:1:1} sunday [leon@localhost ~]$ echo ${string[@]:1:2} sunday hello [leon@localhost ~]$ echo ${string[@]:1} sunday hello
3.1.3 數組的刪除
unset ARRAY
[leon@localhost ~]$ echo ${logs[@]} /home/leon /home/openstack /home/test [leon@localhost ~]$ unset logs[1] #刪除索引為1的數組 [leon@localhost ~]$ echo ${logs[@]} /home/leon /home/test [leon@localhost ~]$ unset logs [leon@localhost ~]$ echo ${logs[@]} [leon@localhost ~]$
3.2 字符串操作
3.2.1 字符串取子串
${string:offset:length} :從第offset個向右取length個字符串
[leon@localhost ~]$ string=a1b2c3d4e5f6 [leon@localhost ~]$ echo ${string} a1b2c3d4e5f6 [leon@localhost ~]$ echo ${string:1:4} 1b2c
${string: -length} :從右向左取length個字符串
[leon@localhost ~]$ echo ${string} a1b2c3d4e5f6 [leon@localhost ~]$ echo ${string: -2} f6
${string#*word} :在string中存儲字符串上,自左而右,查找第一次出現word,刪除字符開始到此word處的所有內容
[leon@localhost ~]$ string=string-hello-myname-is-hello-over [leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string#*hello} -myname-is-hello-over
${string##*word} :在string中存儲字符串上,自左而右,查找最后一次出現word,刪除字符開始到此word處的所有內容
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string#*hello} -myname-is-hello-over [leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string##*hello} -over
${string%word*}在string中存儲的字符串上,自右而左,查找第一次出現的word,刪除字符開始到此word處的所有內容
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string%hello*} string-hello-myname-is-
${string%%word*}在string中存儲的字符串上,自右而左,查找最后一次出現的word,刪除字符開始到此word處的所有內容
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string%%hello*} string-
3.2.2 字符串查找替換
${string/pattern/substi} :替換第一次出現的字符串
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string/hello/hi} string-hi-myname-is-hello-over
${sting//pattern/substi} :替換所有出現過的字符串
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string//hello/hi} string-hi-myname-is-hi-over ${string/pattern} [leon@localhost ~]$ echo ${string//hello/hi} [leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string/hello} string--myname-is-hello-over ${string//pattern}[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string//hello} string--myname-is--over [leon@localhost ~]$
四、流程控制
4.1 選擇分支
4.1.1 條件測試
條件測試中,如果為真,則返回執行狀態為0的值,否則返回執行狀態為非0的值
整型測試:數值之間比較大小 字符型比較
-gt -lt -eq -ge -le > < == != >= <= -n -z
常用文件測試
-e 文件存在
[leon@localhost ~]$ [ -e /tmp/xxxxxxx ] [leon@localhost ~]$ echo $? 1
-d 文件存在且為目錄
[leon@localhost ~]$ [ -d /tmp ] [leon@localhost ~]$ echo $? 0
-f 文件存在且為普通文件
[leon@localhost ~]$ [ -f /tmp ] [leon@localhost ~]$ echo $? 1
-r 文件是否具有可讀權限
[leon@localhost ~]$ [ -r /root ]
[leon@localhost ~]$ echo $?
1
-w 文件是否具有可寫權限
[leon@localhost ~]$ [ -w /home/leon ] [leon@localhost ~]$ echo $? 0
-x 文件是否具有可執行權限
[leon@localhost ~]$ [ -x /home/leon ] [leon@localhost ~]$ echo $? 0
組合條件測試 :在多個條件間實現邏輯運算
與: [ 條件一 -a 條件二 ]
條件一 && 條件二
[leon@localhost ~]$ [ -x /home -a -r /root ] [leon@localhost ~]$ echo $? 1 [leon@localhost ~]$ test -x /home && test -r /root [leon@localhost ~]$ echo $? 1
或: [ 條件一 -o 條件二 ]
條件一 || 條件二
[leon@localhost ~]$ [ -x /home -o -r /root ] [leon@localhost ~]$ echo $? 0 [leon@localhost ~]$ test -x /home || test -r /tmp [leon@localhost ~]$ echo $? 0
非:[ !條件 ]
[leon@localhost ~]$ [ ! -r /home/leon ] [leon@localhost ~]$ echo $? 1
4.1.2 if選擇分支
語法: if 測試條件1;then
選擇分支1
elif 測試條件2;then
選擇分支2
……
elif 測試條件n;then
選擇分支n
else
分支
fi
[leon@localhost ~]$ if true ; then echo true ;else echo false ;fi true[leon@localhost ~]$ [leon@localhost ~]$ if id test1 &>/dev/null ; then echo test1 ;elif id test2 &>/dev/null;then echo test2 ;elif id leon &>/dev/null ;then echo leon ;fi leon [leon@localhost ~]$ if [ $? -eq 0 ] ;then echo ture ;else echo false;fi ture
4.1.3 case選擇分支
語法:case word in
pattern1)
分支1
;;
pattern2)
分支2
;;
patternN)
分支N
;;
*)
分支
;;
esac
[leon@localhost ~]$ case leon in root) id root ;; leon) echo leon ;; *) echo not this user! ;; esac leon [leon@localhost tmp]$ cat testCase.sh #!/bin/bsh # case $1 in 1) echo 1 ;; 2) echo 2 ;; 3) echo 3 ;; *) echo order ;; esac [leon@localhost tmp]$ chmod +x testCase.sh [leon@localhost tmp]$ sh testCase.sh order [leon@localhost tmp]$ ./testCase.sh 1 1
4.2 循環
4.2.1 for循環
語法1: for i in list ;do
list
done
語法2: for ((表達式一;條件表達式;表達式二));do
list
done
[leon@localhost tmp]$ for i in {1..5};do echo $i ;done 1 2 3 4 5 [leon@localhost tmp]$ for ((i=1;i<=5;i++));do echo $i ;done 1 2 3 4 5
4.2.2 while循環
語法1: while 測試條件; do
循環體
done
語法2: while read 變量名;do
循環體
done < /path/to/somefile
[leon@localhost tmp]$ cat testWhile.sh #!/bin/bash # declare -i i=1 while [ $i -le 5 ];do #比較i和5的大小,為真則進入循環,為假則退出循環 echo $i let i++ done [leon@localhost tmp]$ sh testWhile.sh 1 2 3 4 5 [leon@localhost tmp]$ cat testWhile.sh #!/bin/bash # while read userInfo;do echo $userInfo done < /etc/passwd [leon@localhost tmp]$ sh testWhile.sh root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin ...... openstack:x:502:502::/home/openstack:/bin/bash [leon@localhost tmp]$
4.2.3 until循環
語法:until 測試條件; do
循環體
done
[leon@vm tmp]$ cat testUntil.sh #!/bin/bash # declare -i i=5 until [ $i -lt 1 ];do #比較i和1的大小,為假就進入循環,為真則退出循環 echo $i let i-- done [leon@vm tmp]$ sh testUntil.sh 5 4 3 2 1
五、函數及返回值
語法1: function function_name {list}
語法2: function_name () {list}
[leon@vm tmp]$ cat testFunction.sh #!/bin/bash # function display { #定義一個名為display的函數 cat << NODE ------------------- ------meau--------- 1: install os 2: quit ------------------- NODE return 0 #退出函數并返回狀態值0 echo next function_list } view() { display #調用函數 exit 1 #退出shell并返回狀態值1 } view [leon@vm tmp]$ sh testFunction.sh ------------------- ------meau--------- 1: install os 2: quit ------------------- [leon@vm tmp]$ echo $? 1
六、循環控制
continue : 提前進入下一輪循環
[leon@vm tmp]$ cat testContinue.sh #/bin/bash # for (( i=1;i<=2;i++ )) ;do echo outside $i for (( n=1;n<=2;n++ ));do echo inside $n continue #直接進入下一循環 # break echo hello #這個echo語句用于沒有將會執行 done done [leon@vm tmp]$ sh testContinue.sh outside 1 inside 1 inside 2 outside 2 inside 1 inside 2
break :跳出當前循環
[leon@vm tmp]$ cat testContinue.sh #/bin/bash # for (( i=1;i<=2;i++ )) ;do echo outside $i for (( n=1;n<=2;n++ ));do echo inside $n # continue break #退出當前循環 echo hello done done [leon@vm tmp]$ sh testContinue.sh outside 1 inside 1 outside 2 inside 1
七、信號捕捉
信號捕捉:trap 'COMMAND;COMMAND' SINGNAL
[leon@vm tmp]$ cat testTrap.sh #!/bin/bash # trap 'echo exit' SIGINT ping -c 100 www.baidu.com [leon@vm tmp]$ sh testTrap.sh #按ctrl+c時,捕捉到信號。 PING www.a.shifen.com (180.97.33.108) 56(84) bytes of data. 64 bytes from 180.97.33.108: icmp_seq=1 ttl=128 time=29.4 ms 64 bytes from 180.97.33.108: icmp_seq=2 ttl=128 time=29.5 ms ^C --- www.a.shifen.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1278ms rtt min/avg/max/mdev = 29.489/29.530/29.571/0.041 ms exit #退出腳本時執行echo語句輸出
八、總結
shell編程是linux運維人員必須掌握的技能,shell不像其它C、C#、Java等高級編程語言那樣有類和對象,面向對象等概念,但是shell可以有強大的命令支撐。畢竟我們是通過shell來溝通內核,不需要運行在虛擬機上。
原創文章,作者:成吉思汗,如若轉載,請注明出處:http://www.www58058.com/8026
總結的非常不錯,文檔功底很深