1. 程式人生 > >shell編程進階篇

shell編程進階篇

ren root 正常 註意事項 多條 內容 The 使用方法 報錯

上一篇文章介紹的是shell的基礎知識:https://blog.51cto.com/14048416/2355550
??有人會說,shell簡單啊,就是一些命令的堆砌啊,是的一些簡單的操作僅僅執行幾個命令就行了,但是相對一些復雜的業務和要求下,如果只能做到命令的堆砌,那也太有損shell的名聲了。
??小編通過一個例子給大家介紹,如果沒有邏輯和條件,只是命令的堆砌,那麽對維護Linux,是多麽大的災難。


#需求:清除/var/log 下message 日誌文件
命令堆砌

#!/bin/bash       #shell 腳本的標識
cd /var/log       #進入/var/log
cat /dev/null > message  #清空message日誌
echo Logs cleaned up’ #打印清空成功

缺陷

  • 如果不是root用戶不能執行進入/var/log ,和清空message文件
  • 不論是否成功下面的命令都繼續執行
  • 不論腳本是否成功,都會輸出‘clean up’

修改後的腳本

#!/bin/bash       #shell 腳本的標識
LOG_DIR=/tmp/log  #設置一個變量,名稱為/tmp/log
ROOT_UID=$UID    #設置一個變量為當前的用戶的uid
if [ "$UID" -ne 0  ]   #判斷是否是root,root用戶的uid為0
  then 
    echo "Must be root tu run this script" #如果不是輸出,並異常退出腳本
    exit 1
fi
cd $LOG_DIR || {   #如果是root,在判斷是否可以進入/tmp/log
    echo "Cannot change to necessary directory." >&2  #如果不能進入,則也異常退出
    exit 1
}
cat /dev/null>message && echo "Log clean up."  #最後清空之後,輸出一句話並正常退出
exit 0

有些初學者,看見上面的腳本,可能覺得,有些看不懂,沒關系,接下來,小編將會一一講解上面腳本的知識點!

一、條件測試

??在bash的各種流程控制結構中通常要進行各種測試,然後根據測試結果執行不同的操作,有時候也會通過if流程控制語句相結合,使我們可以方便的完成判斷。
語法

格式1:test<測試表達式>
格式2:[ 測試表達式 ]
格式3:[[測試表達式]]

提示:在[[]]中,可以使用&&、||、>、<等操作符進行復雜判斷,但是不能應用於[]

(1)test條件測試

#使用方法:
test -f file   判斷是否是文件
例:test -f file && echo 1 || echo 0    #判斷文件是否存在,存在返回 1 不存在返回0

test ! -f  file   判斷文件是否不存在
例:test !-f file && echo 1 || echo 0    #判斷文件是否存在,不存在返回1  存在返回0

test -d dir 判斷是否是目錄

(2)[]條件測試

#使用方法:
[-f file]  普通文件是否存在
例:[-f file ] && echo 1 || echo 0    #判斷文件是否存在,存在返回 1 不存在返回0
[ ! -f file ]   判斷文件是否不存在
例:[-f file] && echo 1 || echo 0    #判斷文件是否存在,不存在返回1  存在返回0

[-d dir]  #判斷是否是目錄
-s # 判斷文件是否存在並且不為空
-e #判斷文件是否存在,區別於-f,-e表示所有文件
-r #判斷文件是否存在並且是否可讀
-w #判斷文件是否存在並且是否可寫
-x #判斷文件是否存在並且是否可執行
-L #判斷文件是否存在並且是否為鏈接文件
f1 -nt f2  #判斷是否f1比f2新
f1 -ot f2  #判斷是否f1比f2久

(3)[[]]條件測試

#使用方法:
    [[-f file]]  文件是否存在
例:[[-f file ]] && echo 1 || echo 0    #判斷文件是否存在,存在返回 1 不存在返回0
    [[ ! -f file ]]   判斷文件是否不存在
例:[[-f file]] && echo 1 || echo 0    #判斷文件是否存在,不存在返回1  存在返回0

(4)字符串測試操作符

??註意:在使用字符串進行比較時,最好使用””雙引號將其擴起
技術分享圖片

(5)整數操作符

技術分享圖片

(6)邏輯操作符

技術分享圖片

(7)條件測試的舉例

??上面講了諸多概念,現在通過具體的例子讓大家看看條件測試具體怎麽用:

 #這裏聲明兩個變量:file1=/etc/password   file2=/etc/service
 [-f “$file1”] && echo 1||echo 0        $file1存在返回1,不存在返回0
 [-d “$file1”] && echo 1||echo 0       $file1是目錄返回1,不是目錄返回0
 [-s “$file1”] && echo 1||echo 0       $file1是文件並且不為空返回1,否則返回0
 [-e “$file1”] && echo 1||echo 0       $file1存在返回1,不存在返回0
 [-w “$file1”]&&echo 1 ||echo 0        $file1存在並且可寫,返回1,不存在返回0
 [-x “file1”]|| exit 5                    判斷$file1是否可執行,不可執行異常退出
#對字符串的操作
[-z “$value”] || value=”…”           判斷變量是否長度為0,如果為0,賦初值
[“$networkworking”!= “yes”]&&exit 6  通過對變量的判斷,確定是否執行腳本後面的代碼
#復合條件測試
[-f “$file1”-o -e “$file2”] &&echo 1 ||echo 0   file1是文件或者file2存在返回1,否則0
[-f “$file1”-a -e “$file2”] &&echo 1 ||echo 0   file1是文件並且file2存在返回1,否則0
[[-f “$file1”&& -e “$file2”]] &&echo 1 ||echo 0   file1是文件或者file2存在返回1,否則0
[[-f “$file1”|| -e “$file2”]] &&echo 1 ||echo 0   file1是文件並且file2存在返回1,否則0
#整數測試
[ 1 -eq 2 ] &&echo 1||echo 0    等於
[ 1 -gt  2 ] &&echo 1||echo 0    大於
[ 1 -lt  2 ] &&echo 1||echo 0    小於
[ 1 -le  2 ] &&echo 1||echo 0    小於等於
[ 1 -ge  2 ] &&echo 1||echo 0    大於等於
[ 1 -ne  2 ] &&echo 1||echo 0    不等於
註意:及時這裏的兩個數組都是字符串的形式,依然可以比較。
#判斷條件後面執行多條命令
file=/etc/profile
file_bak=${file}.bak
[ -f $file ] && {
cat $file
cp $file $file_bak
mv $file_bak ~/
}

二、控制流程語句

?? 當然,僅僅學習了條件測試,就可以完成很多的功能,但是如果業務相當復雜,功能相當繁多,只是使用條件測試話,不僅完不成具體的功能,對代碼的可讀性也很差。為了勝任更高的要求,接下來介紹控制流程語句,可以說shell有了它,如魚得水吧。

(1)if語句

單分支

 #語法:
 If  [條件]
  then 
命令;
命令;
….
   fi
或者:if[條件];then 命令…; fi

#例:比較大小

num1=10
num2=23
if [ $num1 -gt $num2 ]
  then
    echo "$num1"
else
    echo "$num2"
fi

#判斷系統內存大小,如果小於100M就報警
cur_free=`free -m|awk ‘ /buffers\// {print $NF}‘`
chars="current memory is $cur_free"
if [ $cur_free -lt 100 ]
  then 
    echo "$chars"
    echo "momory is unfree!"
fi

多分支

 #語法:
 多分支:
If  [條件]
  then 
命令;
命令;
….
     else
命令;
命令;
….
   fi
#例:判斷文件是否存在,不存在就創建
 file=/tmp/zy/zy.txt
if [ -f "$file" ]     
  then
    ll $file
  else
    touch $file
fi

if-elif-elif...-else
#語法:

if [條件]
  then
命令;
命令;
  elif [條件]
  then
命令
  else
命令
fi

#例:比較兩個數的大小

read -p "pls input two numbers:" a b
if [ $a -gt $b ]
  then
    echo "$a > $b"
  elif [ $a -eq $b ]
  then
    echo "$a == $b"
  else
    echo "$a < $b"
fi

(2)case語句

 #語法:
 case:
語法:
case “字符串變量”in
pat1) 指令;;
pat2) 指令;;
pat3) 指令;;
*)指令
;;  
esac

#例:

read -p "Please you input is a num:" num
case "$num" in
9[0-9])  #範圍查找
echo A;;
8[0-9])
echo B;;
*)
echo C;;
esac

(3)for循環

for 循環,具體的使用方法有很多,這裏我們使用三個例子說明:

 #例1:(命令作為循環內容)
 for i in `seq 10`
  do
echo $i
done
 #例2:(序列作為循環內容)
 sum=0
for i in {1..100}
  do
    let sum=sum+i
done
echo $sum
#例3:(集合算術操作符的for)
sum=0
for((i=1;i<=100;i++))
  do
    let sum=sum+i
done
echo $sum

(3)while循環

#語法
while [expression]
  do
指令
done

#舉例:

#例1
i=1
sum=0
while ((i<=100))
  do
    let sum=sum+i
    let i++
done
echo $sum

#例2
i=1
sum=0
while [ $i -le 100 ]
  do
    let sum=sum+i
    let i++
done
echo $sum

(4)until循環

#語法
unitl [ expression]
  do
commond;
done

#舉例:

sum=0
i=1
until [ $i -gt 100 ]
  do
    let sum=sum+i
    let i++
done 
echo $sum

註意:unit和for、while的區別就是,until是條件滿足時退出循環,而while和for是條件不滿足是退出循環。

三、shell中的數組

(1)數組的定義:

方法1:array=(value1 value2 valu3 value4)
方法2:array=([index1]=value1 [index2]=value2 [index3]=value3)
方法3:array[0]=value1 array[1]=value2 array[2]=value
方法4:使用命令的方式定義數組:array=($(ls))   將ls命令的執行結果當做數組的值

(2)數組的增、刪、改、查

arr=(1 2 3 4 5 6 7)  #數組的聲明,並賦值
#增
arr[index]=value    #給數組增加元素,index:下標(任意)
#刪
unset arr[index]     #刪除相應index位置的元素
unset arr           #刪除整個數組
#改
arr[index]=value    #給數組增加元素,index:下標(該位置已存在值)
#查:
echo ${arr[index]}   #獲取數組單個元素,index表示數組的下標
echo ${arr[\*]}         #獲取數組的所有元素
echo ${arr[\@]}      #獲取數組的所有元素
echo ${!arr[\*]}        #獲取數組的所有下標
echo ${#arr[@]}                     #查看數組的長度

(3)數組的高級操作

數組內容的截取

? 語法:${arr[*]:number1:len} 從下標number1開始取,取長度為len,獲得一個新的數組。
?

[root@test zy]# arr1=(1 2 3 4)
[root@test zy]# echo ${arr1[*]:0:2} #從下標為0開始取,取兩個元素

數組的替換

? 語法:${arr[*]/valu1/valu2} #將數組中的某個值,替換成其他值(完全替換),生成新數組,數組本身不變。
?

[root@test zy]# arr1=(aa aa bb cc dd)
[root@test zy]# echo ${arr1[*]/aa/bb} #打印bb bb bb cc dd

數組的合並

? 語法:arr=(${arr1[*]} ${arr2[*]}) #arr1和arr2分別是兩個數組
?

[root@test zy]# arr1=(1 2 3)
[root@test zy]# arr2=(4 5 6)
[root@test zy]# arr=(${arr1[]} ${arr2[]})
[root@test zy]# echo ${arr[*]} #打印:1 2 3 4 5 6

數組的遍歷

#使用下標方式遍歷:
arr=(1 2 3 4 5 6)
for i in “${!arr[*]}”
  do
echo “${arr[$i]}”
done
#使用數組的值遍歷
for i in “${arr[*]}”
  do
echo “$i”
done

(4)數組的存儲

註意:Shell中的數組的存儲方式不同,如果在相應的下標中無元素,則無此下標。
技術分享圖片

四、Shell中的函數

?語法

#簡答語法:
函數名(){
指令…
return n
}
#標準語法
function 函數名(){
指令…
return n
}

?shell函數的執行

 #例子
   #!/bin/sh
  #無參數
  function func_test1(){
     return 2
   }
   #有參數
   function func_test2(){
      let  sum=$1+$2   #這裏的$1和$2暫時作為函數的參數
           return $sum  
  }
  #調用參數函數
  func_test1
  echo "$?"
  #調用有參數的函數
  func_test2 1 2
  echo "$?"  #$?用於接受函數的返回值

?自定義函數庫

#第一步:編寫一個腳本(函數庫):
#!/bin/sh
function func1(){…}
function func2(){…}
function func3(){…}
#第二步:(在其他腳本中加載這個函數庫)
#!/bin/sh
source  ./函數庫名     #下載函數庫
func1()    #可以使用函數庫中的函數

?函數使用的註意事項
? ? - 在函數體中,位置參數($1、$2、$3、$#、$*、$@、$?)都可以是函數的參數
? ? - 父腳本的參數則臨時的被函數參數所覆蓋(相當於局部變量)
? ? - $0 仍然是父腳本的名稱
? ? - return 關鍵字用於跳出函數
? ? - 函數調用不能在函數創建之前
? ? - 函數的返回值只能是數字,不然會報錯 :numeric argument required

五、Shell腳本的調試

? ? - 調試自己寫的腳本的方法有很多,這裏小編送大家一張圖:
技術分享圖片

shell編程進階篇