1. 程式人生 > >第二十章 Shell程式設計(上)

第二十章 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 代表小時 分鐘 秒

[

[email protected] shell]# date +%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

把以前的時間戳轉換成時間
[

[email protected] shell]# date -d @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 後面會跟一個數字 給使用者返回該值