第二十章 Shell程式設計(上)
20.1 Shell指令碼介紹
20.2 Shell指令碼結構和執行
20.3 date命令用法
Y年 m月 d日
[[email protected] shell]# date +%Y%m%d
20181026
H小時 M分鐘 S秒
[[email protected] shell]# date +%H-%M-%S
03-56-41
F 代表年月日
[[email protected] shell]# date +%F
2018-10-26
T 代表小時 分鐘 秒
[
03:25:34
s(小寫)時間戳
把當前時間轉換成時間戳
[[email protected] shell]# date +%s
1540539856
把時間戳轉換成時間
[[email protected] shell]# date -d @1540539856
Fri Oct 26 03:44:16 EDT 2018
把以前的時間轉換成時間戳
[[email protected] shell]# date +%s -d "2017-10-26 03:44:16"
1509003856
把以前的時間戳轉換成時間
[
Thu Oct 26 03:44:16 EDT 2017
w 周(0--6)0代表週日
[[email protected] shell]# date +%w
5
W(大寫) 今年的第幾周
[[email protected] shell]# date +%W
43
-1 day 一天以前
date -d "-1 day" +%F
一小時以前
date -d "-1 hour"
一分鐘以前
date -d "-1 min"
-1 month 一月以前
date -d "-1 month" +%F
-1 year 一年以前
date -d "-1 year" +%F
20.4 Shell指令碼中的變數
20.5 Shell指令碼中的邏輯判斷
-gt 大於 -lt 小於 -ge 大於等於 -le 小於等於 -eq 等於 -ne 不等於
[ $a -gt 5 ] 注意方括號裡面有空格
&& 並且 前面的成立的時候才會執行後面的
|| 或者 前面不成立的時候才會執行後面的
20.6 檔案目錄屬性判斷
20.7 if特殊用法
-w 精確匹配一個詞 -q 匹配到不顯示 !沒有過濾到這個使用者
20.8 case判斷(上)
案例
#!/bin/bash
read -p "Please input a number: " n
if [ -z "$n" ]
then
echo "Please input a number."
exit 1
fi
n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
then
echo "Please input a number."
exit 1
fi
if [ $n -lt 60 ] && [ $n -ge 0 ]
then
tag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ]
then
tag=2
elif [ $n -ge 80 ] && [ $n -lt 90 ]
then
tag=3
elif [ $n -ge 90 ] && [ $n -le 100 ]
then
tag=4
else
tag=0
fi
case $tag in
1)
echo "no good"
;;
2)
echo "good"
;;
3)
echo "very good"
;;
4)
echo "great"
;;
*)
echo "The number range is 0-100."
;;
esac
20.10 for迴圈
ls 會以空隔為分隔符,注意!
20.11 while迴圈(上)
20.12 while迴圈(下)
20.13 break跳出迴圈
20.14 continue結束本次迴圈
執行過程
[[email protected] shell]# sh -x continue.sh
++ seq 1 5
+ for i in '`seq 1 5`'
+ echo 1
1
+ '[' 1 -eq 3 ']'
+ echo 1
1
+ for i in '`seq 1 5`'
+ echo 2
2
+ '[' 2 -eq 3 ']'
+ echo 2
2
+ for i in '`seq 1 5`'
+ echo 3
3
+ '[' 3 -eq 3 ']'
+ continue
+ for i in '`seq 1 5`'
+ echo 4
4
+ '[' 4 -eq 3 ']'
+ echo 4
4
+ for i in '`seq 1 5`'
+ echo 5
5
+ '[' 5 -eq 3 ']'
+ echo 5
5
+ echo ok
ok
20.15 exit退出整個指令碼
課堂串講
20.1 shell指令碼介紹
20.2 shell指令碼結構和執行
20.3 date命令用法
20.4 shell指令碼中的變數
20.1 shell指令碼介紹
shell
是一種指令碼語言
。它既有自己的語法規制,可以使用邏輯判斷、迴圈等語法
,也可以自定義函式
。
shell是系統命令的集合
,並且通過主機的語法可以對命令進行判斷等。
shell指令碼可以實現自動化運維
,它能大大增加我們的運維效率。
20.2 Shell指令碼結構和執行
- shell指令碼結構
- 開頭需要加
#!/bin/bash
#!/bin/bash
是告訴系統通過/bin/bash解析器
來解析操作指令碼的 - 以
#
開頭的行作為解釋說明 - 指令碼的名字以
.sh
結尾,用於區分這是一個shell指令碼
- 開頭需要加
1 |
[[email protected] shell]# vim hello.sh |
1 2 3 4 5 |
#!/bin/bash # written by kun # date 2018-7-11 echo "this is first shell script." echo "Hello World!" |
- 執行方法有兩種
- chmod +x 1.sh; ./1.sh
- bash 1.sh
1 2 3 4 |
[[email protected] shell]# chmod a+x hello.sh [[email protected] shell]# ./hello.sh this is first shell script. Hello World! |
也可以
1 2 3 |
[[email protected] shell]# sh hello.sh this is first shell script. Hello World! |
檢視指令碼執行過程 bash -x 1.sh
1 2 3 4 5 |
[[email protected] shell]# sh -x hello.sh + echo 'this is first shell script.' this is first shell script. + echo 'Hello World!' Hello World! |
檢視指令碼是否語法錯誤 bash -n 1.sh
1 2 3 4 5 6 |
#!/bin/bash # written by kun # date 2018-7-11 echo "this is first shell script." echo "Hello World!" for |
1 2 3 |
[[email protected] shell]# sh -n hello.sh hello.sh:行6: 未預期的符號 `newline' 附近有語法錯誤 hello.sh:行6: `for ' |
這裡是for迴圈沒寫完整
20.3 date命令用法
date 顯示當前系統時間 在shell指令碼中才用於標誌時間
1 2 |
[[email protected] shell]# date 2018年 07月 12日 星期四 05:45:33 CST |
命令 | 含義 |
---|---|
date +%Y | 年(4位) |
date +%y | 年(2位) |
date +%m | 月 |
date +%d | 日 |
date +%D | 以 月/日/年 格式顯示日期 |
date +%F | 以 年-月-日 格式顯示日期 |
date +%H | 小時 |
date +%M | 分鐘 |
date +%S | 秒 |
date +%T | 以時:分:秒 格式顯示時間 等於 date +%H:%M:%S |
date +%s | 時間戳 表示距離1970年1月1日到現的秒數 |
date +%w | 這個星期的第幾周 |
date +%W | 今年的第幾周 |
date +%h | 月份縮寫 等於 date +%b |
date -d “-1 day” | 一天前 |
date -d “+1 day” | 一天後 |
date -d “-1 year” | 一年前 |
date -d “-1 month” | 一個月前 |
date -d “-1 hour” | 一小時前 |
date -d “-1 min” | 一分鐘前 |
顯示日期
1 2 3 4 5 6 7 8 |
[[email protected] shell]# date +%Y%m%d 20180712 [[email protected] shell]# date +%D 07/12/18 [[email protected] shell]# date +%F 2018-07-12 |
顯示時間
1 2 |
[[email protected] shell]# date +%T 06:02:30 |
顯示時間戳
1 2 |
[[email protected] shell]# date +%s 1531346417 |
顯示一天後的時間
1 2 |
[[email protected] shell]# date -d "+1 day" +%F 2018-07-13 |
顯示一小時前的時間
1 2 |
[[email protected] shell]# date -d "-1 hour" +%T 05:20:06 |
用時間戳來顯示日期
1 2 |
[[email protected] shell]# date -d @1531346417 2018年 07月 12日 星期四 06:00:17 CST |
指定時間來顯示對應的時間戳
1 2 |
[[email protected] shell]# date +%s -d"2018-07-13 06:02:30" 1531432950 |
cal 顯示系統日曆
1 2 3 4 5 6 7 8 |
[[email protected] shell]# cal 七月 2018 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
20.4 Shell指令碼中的變數
- 當指令碼中使用某個字串較頻繁並且字串長度很長時就應該使用變數代替,既可以更加工作效率,也可以方便更改
- 使用條件語句時,常使用變數 if [ $a -gt 1 ]; then … ; fi
- 引用某個命令的結果時,用變數替代 n=`wc -l 1.txt`
- 寫和使用者互動的指令碼時,變數也是必不可少的 read -p “Input a number: “ n; echo $n 如果沒寫這個n,可以直接使用$REPLY
- 內建變數 $0, $1, $2…
$0
表示指令碼本身檔名
,$1
表示第一個引數
,$2
第二個 ….$#
表示引數個數
- 數學運算a=1;b=2;
c=$(($a+$b))
或者$[$a+$b]
20.5 shell指令碼中的邏輯判斷
20.6 檔案目錄屬性判斷
20.7 if特殊用法
20.8/20.9 case判斷
20.5 Shell指令碼中的邏輯判斷
語法格式
格式1:if 條件 ; then 語句; fi
指令碼形式
1 2 3 4 5 6 7 8 |
[[email protected] shell]# vim if1.sh #!/bin/bash a=3 if [ $a -gt 2 ] then echo ok fi |
1 2 |
[[email protected] shell]# sh if1.sh ok |
命令列形式
1 2 3 |
[[email protected] shell]# a=3 [[email protected] shell]# if [ $a -gt 2 ];then echo ok;fi ok |
或者
1 2 3 4 5 |
[[email protected] shell]# a=3 [[email protected] shell]# if [ $a -gt 2 ] > then echo ok > fi ok |
格式2:if 條件; then 語句; else 語句; fi
1 2 3 4 5 6 7 8 9 10 |
[[email protected] shell]# vim if2.sh #!/bin/bash a=1 if [ $a -gt 2 ] then echo ok else echo nook fi |
1 2 3 4 5 |
[[email protected] shell]# sh -x if2.sh + a=1 + '[' 1 -gt 2 ']' + echo nook nook |
格式3:if 條件1; then 語句1;elif 條件2; then 語句2; else 語句3; fi
意思為符合條件1則執行語句1,不符合則再判斷是否符合條件2,都不符合則執行語句3
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[[email protected] shell]# vim if3.sh #!/bin/bash a=2 if [ $a -eq 3 ] then echo "the num = 3" elif [ $a -gt 3 ] then echo "the num > 3" else echo "the num < 3" fi |
1 2 3 4 5 6 |
[[email protected] shell]# sh -x if3.sh + a=2 + '[' 2 -eq 3 ']' + '[' 2 -gt 3 ']' + echo 'the num < 3' the num < 3 |
邏輯判斷表示式:if [ $a -gt $b ]
if [ $a -lt 5 ]
if [ $b -eq 10 ]
也可以使用數學形式 if (($a>$b))
if(($a<5))
if(($b==10))
為了方便記憶 我們可以選擇記憶帶[]格式的表示式,但要注意[]兩側都是空格
引數 | 數學符號 | 含義 |
---|---|---|
-gt | > | 大於(greater than) |
-lt | < | 小於 (less than) |
-eq | == | 等於(equal) |
-ge | >= | 大於等於 |
-le | <= | 小於等於 |
-ne | != | 不等於 |
可以使用 &&
||
結合多個條件if [ $a -gt 5 ] && [ $a -lt 10 ]
&&表示並且if [ $b -gt 5 ] || [ $b -lt 3 ]
||表示或者
20.6 檔案目錄屬性判斷
引數 | 含義 |
---|---|
[ -f file ] | 判斷是否是普通檔案,且存在 |
[ -d file ] | 判斷是否是目錄,且存在 |
[ -e file ] | 判斷檔案或目錄是否存在 |
[ -r file ] | 以當前使用者來判斷檔案是否可讀 |
[ -w file ] | 以當前使用者來判斷檔案是否可寫 |
[ -x file ] | 以當前使用者來判斷檔案是否可執行 |
判斷檔案是否存在
1 2 3 4 5 6 7 8 9 10 |
[[email protected] shell]# vim file1.sh #!/bin/bash f="/tmp/test" if [ -f $f ] then echo "$f exist" else touch $f fi |
第一次檔案不存在則建立檔案
1 2 3 4 |
[[email protected] shell]# sh -x file1.sh + f=/tmp/test + '[' -f /tmp/test ']' + touch /tmp/test |
第二次檔案存在
1 2 3 4 5 |
[[email protected] shell]# sh -x file1.sh + f=/tmp/test + '[' -f /tmp/test ']' + echo '/tmp/test exist' /tmp/test exist |
判斷檔案/目錄是否存在
1 2 3 4 5 6 |
#!/bin/bash f="/tmp/test" if [ -e $f ] then touch $f fi |
即使已經存在了再touch則會更改檔案/目錄的是時間
判斷檔案是否可讀
1 2 3 4 5 6 7 8 |
[[email protected] shell]# vim file2.sh #!/bin/bash f="/tmp/test" if [ -r $f ] then echo "$f readable" fi |
1 2 |
[[email protected] shell]# sh file2.sh /tmp/test readable |
有時候為了方便可以寫成下面程式碼
1 2 3 |
#!/bin/bash f="/tmp/test" [ -f $f ] && rm -f $f |
它表示檔案存在則執行rm語句 等同於
1 2 3 4 5 6 |
#!/bin/bash f="/tmp/test" if [ -f $f ] then rm -f $f fi |
[ -f $f ] || rm -f $f
它表示檔案不存在則執行rm語句 等同於[ ! -f $f ] && rm -f $f
20.7 if特殊用法
引數 | 含義 |
---|---|
[ -z “$a” ] | 表示當變數a的值為空 |
[ -n “$a” ] | 表示當變數a的值不為空 |
判斷變數是否不為空
1 2 3 4 5 6 7 8 |
[[email protected] shell]# vim file3.sh #!/bin/bash f=/tmp/test if [ -n "$f" ] then echo ok fi |
1 2 |
[[email protected] shell]# sh file3.sh ok |
-
其他特殊用法
-
使用命令來做判斷條件
1 2
[[email protected] shell]# if grep -wq 'root' /etc/passwd;then echo root exist;fi root exist
grep -w 'root'
只搜尋root此單詞-q
不在螢幕打印出來 - 使用! 在引數前 表示取反 [ ! -e file ] 表示檔案不存在
- 中括號中不能使用<,>,==,!=,>=,<=這樣的符號
-
20.8/20.9 case判斷
語法格式
1 2 3 4 5 6 7 8 9 10 11 |
case 變數名 in value1) command ;; value2) command ;; *) commond ;; esac |
在case程式中,可以在條件中使用|
,表示或
的意思, 比如
1 2 3 |
2|3) command ;; |
判斷學生的成績指令碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
[[email protected] shell]# vim case1.sh #!/bin/bash read -p "Please input number: " n #讓使用者輸入數字 if [ -z "$n" ] then echo "Please input number: " exit 1 fi #判斷使用者是否沒填數字 n1=`echo $n|sed 's/[0-9]//g'` if [ ! -z "$n1" ] then echo "Please input number: " exit 1 fi #判斷使用者是否填純數字 if [ $n -lt 60 ] then tag=1 elif [ $n -ge 60 ] && [ $n -lt 80 ] then tag=2 elif [ $n -ge 80 ] && [ $n -lt 90 ] then tag=3 elif [ $n -ge 90 ] && [ $n -le 100 ] then tag=4 else tag=0 fi #給分數賦值給tag case $tag in 1) echo "bu ji he" ;; 2) echo "liang hao" ;; 3) echo "you xiu" ;; 4) echo "fei chang bang" ;; *) echo "The number range is 0-100" ;; esac #對tag進行判斷 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[[email protected] shell]# sh -x case1.sh + read -p 'Please input number: ' n Please input number: asdfsad + '[' -z asdfsad ']' ++ echo asdfsad ++ sed 's/[0-9]//g' + n1=asdfsad + '[' '!' -z asdfsad ']' + echo 'Please input number: ' Please input number: + exit 1 [[email protected] shell]# sh -x case1.sh + read -p 'Please input number: ' n Please input number: 89 + '[' -z 89 ']' ++ echo 89 ++ sed 's/[0-9]//g' + n1= + '[' '!' -z '' ']' + '[' 89 -lt 60 ']' + '[' 89 -ge 60 ']' + '[' 89 -lt 80 ']' + '[' 89 -ge 80 ']' + '[' 89 -lt 90 ']' + tag=3 + case $tag in + echo 'you xiu' you xiu |
20.10 for迴圈
20.11/20.12 while迴圈
20.13 break跳出迴圈
20.14 continue結束本次迴圈
20.15 exit退出整個指令碼
20.10 for迴圈
語法格式
1 |
for 變數名 in 條件; do …; done |
計算出0到100的總和
1 2 3 4 5 6 7 8 9 |
[[email protected] shell]# vim for1.sh #!/bin/bash sum=0 for i in `seq 1 100` do sum=$[$i+$sum] done echo $sum |
1 2 |
[[email protected] shell]# sh for1.sh 5050 |
遍歷/etc目錄並把目錄列出來
1 2 3 4 5 6 7 8 |
[[email protected] shell]# vim for2.sh #!/bin/bash cd /etc for i in `ls /etc` do [ -d $i ] && ls $i done |
注意
:for迴圈是以空格
作為分隔符 ,因此檔名中到空格的要注意
1 2 3 4 5 6 7 8 |
[[email protected] for]# touch 1 2 [[email protected] for]# touch 3\ 4.txt [[email protected] for]# ll 總用量 0 -rw-r--r-- 1 root root 0 7月 14 05:07 1 -rw-r--r-- 1 root root 0 7月 14 05:07 2 -rw-r--r-- 1 root root 0 7月 14 05:07 3 4.txt |
1 2 3 4 5 |
[[email protected] for]# for i in `ls .`;do echo $i;done 1 2 3 4.txt |
這裡for迴圈把3 4.txt 分為了兩個檔案
20.11/20.12 while迴圈
語法格式
1 |
while 條件; do … ; done |
每隔30秒檢視系統負載,當大於10時發郵件
1 2 3 4 5 6 7 8 9 10 11 12 |
[[email protected] shell]# vim while1.sh #!/bin/bash while : do load=`w|head -1|awk -F 'load average: ' '{print $2}'|cut -d . -f1` if [ $load -gt 10 ] then /usr/local/sbin/mail.py [email protected] "load high" "$load" fi sleep 30 done |
1 2 3 4 5 6 7 8 9 |
[[email protected] shell]# sh -x while1.sh + : ++ head -1 ++ awk -F 'load average: ' '{print $2}' ++ cut -d . -f1 ++ w + load=0 + '[' 0 -gt 10 ']' + sleep 30 |
:
ture
1
都是代表為正
因此while :
就是一個死迴圈
為了不讓while指令碼不意外終止 可以使用screen
命令 再到screen下執行此指令碼
提示讓使用者只能輸入數字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[[email protected] shell]# vim while2.sh #!/bin/bash while : do read -p "Please input a number: " n if [ -z "$n" ] then echo "Please input sth!" continue fi ##判斷使用者是否直接回車 n1=`echo $n|sed 's/[0-9]//g'` if [ -n "$n1" ] then echo "Please input number!" continue fi #判斷使用者是否輸入純數字 echo $n break done |
1 2 3 4 5 6 7 |
[[email protected] shell]# sh while2.sh Please input a number: Please input sth! Please input a number: a Please input number! Please input a number: 1 1 |
echo $n|sed 's/[0-9]//g
把數字給過濾掉來判斷是否有其他字元
20.13 break跳出迴圈
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[[email protected] shell]# vim break.sh #!/bin/bash for i in `seq 1 5` do echo $i if [ $i -eq 3 ] then break fi echo $i done echo aaaa |
1 2 3 4 5 6 7 |
[[email protected] shell]# sh break.sh 1 1 2 2 3 aaaa |
20.14 continue結束本次迴圈
忽略continue之下的程式碼,直接進行下一次迴圈
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[[email protected] shell]# vim continue.sh #!/bin/bash for i in `seq 1 5` do echo $i if [ $i -eq 3 ] then continue fi echo $i done echo aaaa |
1 2 3 4 5 6 7 8 9 10 11 |
[[email protected] shell]# sh continue.sh 1 1 2 2 3 4 4 5 5 aaaa |
20.15 exit退出整個指令碼
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[[email protected] shell]# vim exit.sh #!/bin/bash for i in `seq 1 5` do echo $i if [ $i -eq 3 ] then exit 1 fi echo $i done echo aaaa |
1 2 3 4 5 6 |
[[email protected] shell]# sh exit.sh 1 1 2 2 3 |
返回exit 後面設定的值
1 2 |
[[email protected] shell]# echo $? 1 |
總結
break
,continue
都是在for
while
迴圈中使用的- break出現時候會跳出本次迴圈 直接忽略掉了break後面的程式碼
- continue出現時候也會忽略掉了continue後面的程式碼並重新再來執行迴圈
- exit直接跳出指令碼 一般exit 後面會跟一個數字 給使用者返回該值