linux之Shell詳述
阿新 • • 發佈:2022-03-21
目錄
- Shell
Shell
Shell是一門程式語言。學習Shell的目的是提高(批量)執行多條命令的效率。
1、學習Shell之前需要了解的問題
1.1 編譯型語言和解釋型語言
編譯型語言:需要編譯器將程式碼編譯成二進位制檔案,例如:C語言、Java語言、Golang語言。
解釋型語言:需要解析器在程式碼需要執行的時候將程式碼編譯成二進位制資料,例如:Python、Shell。
1.2 強一致性和弱一致性
強一致性是變數必須跟設定資料型別保持一致。
弱一致性是變數可以根據不同場景自動變換自己的資料型別。
2、Shell語言入門
2.1 Shell代表的兩層意思
1.shell指的是它本身這門語言。
2.伺服器中的命令解析器,例如:bash、sh
[root@mysql01 ~]# chsh -l # 檢視伺服器已安裝的解析器
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
2.2 Shell程式書寫規範
# 注意:
1.shell指令碼通常以`.sh`結尾
2.需要在shell指令碼的第一行指定解析器
#!/bin/bash
命令
2.3 Shell中的變數
# 什麼是變數
量:指的是記錄事物的狀態。
變:指的是事物的狀態可以發生改變。
# 為什麼要使用變數?
程式執行過程中本質上就需要一些列的變化。
# 變數的使用原則:
先定義,後使用。
2.3.1 定義:變數名=值
[root@dxd ~]# name="張飛"
# 注意:等號兩邊不能有空格(在shell解析器中,認為空格代表分隔符)
2.3.2 引用:使用$符取值
[root@dxd ~]# name="張飛"
[root@dxd ~]# echo $name
張飛
2.3.3 刪除:unset 變數名
[root@dxd ~]# echo $name
張飛
[root@dxd ~]# unset name
[root@dxd ~]# echo $name
2.3.4 變數的命名規則
1.以字母開頭:name
2.使用中劃線或者下劃線做單詞之間的連結:city_name;city-name
3.同類型的變數用數字區分:name1;name2
4.變數名區分大小寫,大小寫不同的話就不是同一個變數:student;Student
2.3.5 變數值的來源
# 1.直接賦值
[root@dxd ~]# name="張飛"
# 2.從位置引數中獲取:例如在指令碼執行時,可以在執行指令碼後面跟引數
[root@dxd ~]# ./first.sh n m g 3 4 4 4 4 5 5 5 5 5
n
m
g
5
[root@dxd ~]# vim first.sh
#!/bin/bash
echo $1
echo $2
echo $3
echo ${11}
[root@mysql01 ~]# chmod +x ./first.sh
# 3.使用者輸入
[root@dxd ~]# ./first1.sh
請輸入:345
345
[root@dxd ~]# cat first1.sh
#!/bin/bash
read -p "請輸入姓名:" name
echo $name
2.3.6 系統預定義變數
預定義變數 | 解釋 |
---|---|
$* | 代表所有的引數 |
$@ | 所有的引數 |
$# | 引數的個數 |
$$ | 當前程序的PID |
$? | 代表上一條命令的返回值(預設:0代表成功,其他代表失敗,最大128) |
[root@mysql01 ~]# ./first3.sh 0 1 2 3 4 55 66
0 1 2 3 4 55 66
0 1 2 3 4 55 66
7
2607
0
[root@mysql01 ~]# ./first3.sh 0 1 2 3 "4 55 66"
0 1 2 3 4 55 66
0 1 2 3 4 55 66
5
2609
0
[root@mysql01 ~]# cat first3.sh
#!/bin/bash
echo $*
echo $@
echo $#
echo $$
echo $?
2.4 Shell中的常量
相對於變數來說,常量就是不可以變化的值。
[root@dxd ~]# x=100
[root@dxd ~]# readonly x
[root@dxd ~]# echo $x
100
[root@dxd ~]# x=200
-bash: x: readonly variable # 報錯:提示x為只讀變數
3、Shell中的資料型別
# 在學習shell之前,需要了解的幾個問題
1.什麼是資料?
資料即變數的值,如age=18,18則是我們儲存的資料。
2.為什麼需要這麼多的資料型別?
資料型別就是用來描述變數值(資料變化的型別)的型別。為了儘可能的減少變數值佔用空間的大小,提升空間效率。
3.1 數字型別
數字型別就是用來儲存數字的。
[root@dxd ~]# age=10
[root@dxd ~]# salary=3.1
3.2 字串型別
字串型別就是用來儲存字元的。
# 注意:
雙引號(""):弱引用,保留特殊字元的含義。
單引號(''):強引用,取消特殊字元的含義。
[root@dxd ~]# name='張飛'
[root@dxd ~]# address='上海市青浦區xxx'
[root@dxd ~]# echo "$name 住在 $address"
張飛 住在 上海市青浦區xxx
[root@dxd ~]# echo '$name 住在 $address'
$name 住在 $address
3.3 陣列
1.什麼是陣列?
陣列就是一系列元素的集合,一個數組內可以存放多個元素。
2.為什麼要用陣列?
為了將多個元素彙總到一起,避免單獨定義。
3.陣列的分類
普通陣列(列表):只能夠使用整數作為索引。
關聯陣列(字典):可以使用字串作為陣列的索引。
3.4 普通陣列
3.4.1 宣告陣列的四種方式
- 方式一:直接宣告
[root@dxd ~]# array=("張飛", 18)
[root@dxd ~]# declare -a
declare -a array='([0]="張飛," [1]="18")'
- 方式二:指定索引
[root@dxd ~]# array=([2]=19 [1]="關羽" [0]="未婚")
[root@dxd ~]# declare -a
declare -a array='([0]="未婚" [1]="關羽" [2]="19")'
- 方式三:依次賦值
[root@dxd ~]# array[0]="已婚"
[root@dxd ~]# array[1]="劉備"
[root@dxd ~]# declare -a
declare -a array='([0]="已婚" [1]="劉備" [2]="19")'
- 方式四:利用執行命令的結果賦值
[root@dxd ~]# array1=(`ls`)
[root@dxd ~]# declare -a
declare -a array1='([0]="1.txt" [1]="first.sh" [2]="mysql80-community-release-el7-3.noarch.rpm" [3]="nginx-1.20.2" [4]="nginx-1.20.2.tar.gz" [5]="test" [6]="聖誕樹.py")'
3.4.2 訪問陣列的兩種方式
# 注意:正向索引從`0`開始,反向索引從`-1`開始。
- 方式一:正向索引
[root@dxd ~]# declare -a
declare -a array1='([0]="1.txt" [1]="first.sh" [2]="mysql80-community-release-el7-3.noarch.rpm" [3]="nginx-1.20.2" [4]="nginx-1.20.2.tar.gz" [5]="test" [6]="聖誕樹.py")'
[root@dxd ~]# echo ${array1[2]}
mysql80-community-release-el7-3.noarch.rpm
- 方式二:反向索引
[root@dxd ~]# declare -a
declare -a array1='([0]="1.txt" [1]="first.sh" [2]="mysql80-community-release-el7-3.noarch.rpm" [3]="nginx-1.20.2" [4]="nginx-1.20.2.tar.gz" [5]="test" [6]="聖誕樹.py")'
[root@dxd ~]# echo ${array1[-5]}
mysql80-community-release-el7-3.noarch.rpm
3.5 關聯陣列
3.5.1 宣告關聯陣列的兩種方式
- 方式一:賦值宣告
[root@dxd ~]# declare -A info
[root@dxd ~]# info['name']='張飛'
[root@dxd ~]# info['age']=19
- 方式二:直接宣告
[root@dxd ~]# declare -A info='([name]="關羽" [age]=18)'
3.5.2 訪問關聯陣列
[root@dxd ~]# echo ${info["name"]}
關羽
4、變數值操作
4.1 獲取變數值的長度
語法:${#變數名}
[root@dxd ~]# name='World'
[root@dxd ~]# echo ${#name}
5
[root@dxd ~]# echo $name | wc -L
5
[root@dxd ~]# echo $name | awk '{print length}'
5
4.2 切片
語法:${變數名:開始位置:步長}
[root@dxd ~]# echo ${name:1} # 從第二個位置往後
orld
[root@dxd ~]# echo ${name:1:2} # 從第二個位置往後取兩位數
or
[root@dxd ~]# echo ${name::2} # 從第一個位置開始往後取兩位數
Wo
4.3 截斷
[root@dxd ~]# url='www.baidu.com'
[root@dxd ~]# echo ${url#www.}
baidu.com
[root@dxd ~]# echo ${url#*w.}
baidu.com
------------------
[root@dxd ~]# echo ${url%.com}
www.baidu
4.4 替換
[root@dxd ~]# echo $url
www.baidu.com
[root@dxd ~]# echo ${url/baidu/aliyun}
www.aliyun.com
4.5 變數的替代
${x:-臨時變數資訊}:如果變數不存在,則使用預設值。
[root@dxd ~]# echo $name1
[root@dxd ~]# echo ${name1-"西施"}
西施
[root@dxd ~]# name1="呂布"
[root@dxd ~]# echo ${name1-"西施"}
呂布
${x:=新的變數資訊}:如果變數不存在,則使用預設值,並且將預設值賦值給變數。
[root@dxd ~]# echo $name1
[root@dxd ~]# echo ${name1:="關羽"}
關羽
[root@dxd ~]# echo $name1
關羽
${x:?設定變數提示資訊}:如果執行的變數不存在,則使用預設的提示資訊。
[root@dxd ~]# echo $dfsdfasdfd
-bash: dfsdfasdfd: 未找到命令
[root@dxd ~]# echo ${dsfsdafds:?"該變數未定義"}
-bash: dsfsdafds: 該變數未定義
${x:+有設定變數提示資訊}:變數存在則列印相關資訊
[root@dxd ~]# echo $name1
關羽
[root@dxd ~]# echo ${name1:+該變數存在}
該變數存在
[root@dxd ~]# unset name1
[root@dxd ~]# echo ${name1:+該變數存在}
4.6 let計算
[root@dxd ~]# n=100
[root@dxd ~]# let n=$n+1
[root@dxd ~]# echo $n
101
4.7 取命令的結果賦值給變數
反引號(``)
$():
[root@dxd ~]# pid=`ps -ef | grep 30043 | head -1 | awk '{print $3}'`
[root@dxd ~]# echo $pid
1112
[root@dxd ~]# pid=$(ps -ef | grep 30043 | head -1 | awk '{print $3}')
[root@dxd ~]# echo $pid
1112
5、元字元
元字元是指能夠被Shell解析的特殊字元。
5.1 算數運算子
算數運算子主要是用來做一些簡單運算。
1、運算子
+ : 加法運算
- : 減法運算
* : 乘法運算
/ : 除法運算
% : 取模運算
2、bc運算
[root@dxd ~]# echo `echo 1+1 | bc`
2
# 保留兩位小數
[root@dxd ~]# echo `echo "scale=2;1.1/1.2" | bc`
.91
3、expr運算
[root@dxd ~]# echo `expr 5 / 3`
1
注意:expr只支援整數運算。
4、$(())運算
[root@dxd ~]# echo $((5 / 3))
1
注意:$(())只支援整數運算。
5、$[]運算
[root@dxd ~]# echo $[5/3]
1
注意:$[]只支援整數運算。
6、let
[root@dxd ~]# let res=5/3
[root@dxd ~]# echo $res
1
注意:let只支援整數運算。
5.2 測試運算子
主要是用來探測某一個檔案的屬性的。
1、測試檔案狀態
1.1、測試是否是目錄
[root@dxd ~]# test -d /root/nginx-1.20.2
[root@dxd ~]# echo $?
0
[root@dxd ~]# test -d /root/first.sh
[root@dxd ~]# echo $?
1
[root@dxd ~]# [ -d /root/nginx-1.20.2 ]; echo $?
0
[root@dxd ~]# [ -d /root/first.sh ]; echo $?
1
1.2、測試檔案是否非空
[root@dxd ~]# cat first.sh
#!/bin/bash
echo $$
sleep 100
[root@dxd ~]# cat first1.sh
[root@dxd ~]# [ -s /root/first.sh ];echo $?
0
[root@dxd ~]# [ -s /root/first1.sh ];echo $?
1
[root@dxd ~]#
1.3、測試檔案是否是標準檔案
[root@dxd ~]# [ -f /root/first.sh ];echo $?
0
[root@dxd ~]# [ -f /root/nginx-1.20.2 ];echo $?
1
1.4、判斷檔案是否可寫
[root@dxd ~]# [ -w /root/1.txt ];echo $?
0
[root@dxd ~]# su - test
最後一次失敗的登入:三 3月 9 15:10:14 CST 2022從 124.221.117.45ssh:notty 上
最有一次成功登入後有 42 次失敗的登入嘗試。
[test@dxd ~]$ [ -w /root/1.txt ];echo $?
1
1.5、判斷檔案是否可讀
[test@dxd ~]$ [ -r /root/1.txt ];echo $?
1
[test@dxd ~]$ exit
logout
[root@dxd ~]# [ -r /root/1.txt ];echo $?
0
1.6、判斷檔案是否可執行
[root@dxd ~]# [ -x /root/first.sh ];echo $?
0
[root@dxd ~]# [ -x /root/1.txt ];echo $?
1
1.7、判斷是否是軟連線檔案
[root@dxd ~]# [ -L /bin ];echo $?
0
[root@dxd ~]# [ -L /root ];echo $?
1
1.8、判斷是否是一個磁碟檔案
[root@dxd /]# [ -c /proc/tty ];echo $?
1
5.3 字串測試運算子
主要是用來判斷字串是否相等。
1、判斷兩個字串是否相等
[root@dxd /]# [ "aaa" == "bbb" ] ; echo $?
1
[root@dxd /]# [ "aaa" == "aaa" ] ; echo $?
0
2、判斷兩個字串是否不相等
[root@dxd /]# [ "aaa" != "aaa" ] ; echo $?
1
3、判斷字串是否為空
[root@dxd /]# [ -z "" ];echo $?
0
[root@dxd /]# [ -z "123" ];echo $?
1
4、判斷字串是否不為空
[root@dxd /]# [ -n "123" ];echo $?
0
[root@dxd /]# [ -n "" ];echo $?
1
5.4 數值測試運算子
1、數值測試運算子
運算子 | 解釋 |
---|---|
-eq | 等於 |
-ne | 不等於 |
-gt | 大於 |
-lt | 小於 |
-ge | 大於等於 |
-le | 小於等於 |
-a | 並且 |
-o | 或者 |
2、等於(-eq)
[root@dxd ~]# [ 123 -eq 234 ];echo $?
1
[root@dxd ~]# [ 123 -eq 123 ];echo $?
0
3、不等於(-ne)
[root@dxd ~]# [ 123 -ne 234 ];echo $?
0
[root@dxd ~]# [ 123 -ne 123 ];echo $?
1
4、大於(-gt)
[root@dxd ~]# [ 123 -gt 234 ];echo $?
1
[root@dxd ~]# [ 1203 -gt 234 ];echo $?
0
5、小於(-lt)
[root@dxd ~]# [ 1203 -lt 234 ];echo $?
1
[root@dxd ~]# [ 123 -lt 234 ];echo $?
0
6、大於等於(-ge)
[root@dxd ~]# [ 123 -ge 234 ];echo $?
1
[root@dxd ~]# [ 234 -ge 234 ];echo $?
0
[root@dxd ~]# [ 2340 -ge 234 ];echo $?
0
7、小於等於(-le)
[root@dxd ~]# [ 234 -le 123 ];echo $?
1
[root@dxd ~]# [ 234 -le 1230 ];echo $?
0
[root@dxd ~]# [ 234 -le 234 ];echo $?
0
8、並且(-a)
[root@dxd ~]# [ 123 -eq 123 -a 234 -eq 234 ];echo $?
0
[root@dxd ~]# [ 123 -eq 123 -a 234 -eq 2304 ];echo $?
1
9、或者(-o)
[root@dxd ~]# [ 123 -eq 123 -o 234 -eq 2304 ];echo $?
0
5.5 關係運算符
運算子 | 解釋 |
---|---|
< | 小於 |
> | 大於 |
<= | 小於等於 |
>= | 大於等於 |
== | 等於 |
!= | 不等於 |
&& | 並且 |
兩個豎向 | 或者 |
; | 前後都執行 |
1、小於
[root@dxd ~]# (($x<100));echo $?
1
[root@dxd ~]# (($x==100));echo $?
0
2、大於
[root@dxd ~]# (($x>100));echo $?
1
[root@dxd ~]# (($x==100));echo $?
0
3、小於等於
[root@dxd ~]# (($x<=100));echo $?
0
4、大於等於
[root@dxd ~]# (($x>=100));echo $?
0
5、等於
[root@dxd ~]# (($x==100));echo $?
0
6、不等於
[root@dxd ~]# (($x!=100));echo $?
1
7、並且
[root@dxd ~]# echo 123 && echo 456
123
456
[root@dxd ~]# echso 123 && echo 456
-bash: echso: 未找到命令
8、或者
[root@dxd ~]# echso 123 || echo 456
-bash: echso: 未找到命令
456
[root@dxd ~]# echo 123 || echo 456
123
9、前後都執行
[root@dxd ~]# echo 123 ; echo 456
123
456
[root@dxd ~]# echso 123 ; echo 456
-bash: echso: 未找到命令
456
[root@dxd ~]# echo 123 ; ecsho 456
123
-bash: ecsho: 未找到命令
5.6 賦值運算子
運算子 | 解釋 |
---|---|
= | 直接賦值 |
+= | 先加法後等於 |
*= |
先乘法後賦值 |
/= | 先除法後賦值 |
%= | 先取模後賦值 |
1、直接賦值
[root@dxd ~]# x=100
2、先加法後等於
[root@dxd ~]# let x+=1
[root@dxd ~]# echo $x
101
3、先乘法後賦值
[root@dxd ~]# let x*=2
[root@dxd ~]# echo $x
202
4、先除法後賦值
[root@dxd ~]# let x/=2
[root@dxd ~]# echo $x
101
5、先取模後賦值
[root@dxd ~]# let x%=3
[root@dxd ~]# echo $x
2
5.7 補充
[[]]: 與 [] 基本上一致,不同的是[[]]支援正則
[test@dxd ~]$ [[ "$USER" =~ ^t ]];echo $?
0
[test@dxd ~]$ [[ "$USER" =~ t$ ]];echo $?
0
[test@dxd ~]$ [ "$USER" =~ t$ ];echo $?
-bash: [: =~: binary operator expected
2
6、流程控制之IF
if是一個條件判斷的流程控制。
6.1 單分支IF
語法:if 條件判斷; then 判斷體 fi
# 案例:判斷一個小姐姐的年紀是否是18。
[root@dxd ~]# ./first.sh
是18歲
[root@dxd ~]# cat first.sh
#!/bin/bash
old=18
if [ $old -eq 18 ];then
echo "是18歲"
fi
6.2 雙分支IF
語法:if 條件判斷; then 判斷體 else 判斷體 fi
[root@dxd ~]# ./first.sh
是18歲
[root@dxd ~]# vim first.sh
[root@dxd ~]# ./first.sh
不是18歲
[root@dxd ~]# cat first.sh
#!/bin/bash
old=19
if [ $old -eq 18 ];then
echo "是18歲"
else
echo "不是18歲"
fi
6.3 多分支IF
語法:if 條件判斷; then 判斷體 elif 判斷體 else 判斷體 fi
[root@dxd ~]# cat first.sh
#!/bin/bash
read -p "請輸入你的性別:" sex
if [ "$sex" == "男" ];then
echo "性別:男"
elif [ "$sex" == "女" ];then
echo "性別:女"
else
echo "保密"
fi
[root@dxd ~]# ./first.sh
請輸入你的性別:男
性別:男
[root@dxd ~]# ./first.sh
請輸入你的性別:
保密
[root@dxd ~]#
6.4 案例
# 2.傳入一個檔案路徑,判斷檔案的型別
[root@dxd ~]# ./first1.sh
請輸入檔案路徑:、^H、
不是一個路徑
[root@dxd ~]# ./first1.sh
請輸入檔案路徑:/root
是一個路徑
[root@dxd ~]# cat first1.sh
#!/bin/bash
read -p "請輸入檔案路徑:" paths
if [ -d $paths ];then
echo "是一個路徑"
else
echo "不是一個路徑"
fi
# 2.判斷80埠是否正在被使用
[root@dxd ~]# cat first1.sh
#!/bin/bash
netstat -nutlp | grep -w '\b80\b' &>/dev/null
if [ $? -eq 0 ];then
echo "80埠正在被使用"
else
echo "80埠未被使用"
fi
[root@dxd ~]# ./first1.sh
80埠正在被使用
7、流程控制之case語句
語法:
case [變數] in
判斷1)
判斷之後需要執行的內容
;;
判斷2)
判斷之後需要執行的內容
;;
判斷3)
判斷之後需要執行的內容
;;
*)
其他需要執行的內容
esac
7.1案例
# 案例1:判斷一個使用者是否是超級使用者
[root@dxd ~]# ./first.sh
請輸入使用者名稱:default
普通使用者
[root@dxd ~]# ./first.sh
請輸入使用者名稱:test
未知使用者
[root@dxd ~]# cat first.sh
#!/bin/bash
read -p '請輸入使用者名稱:' users
case $users in
root)
echo "超級管理員"
;;
default)
echo "普通使用者"
;;
*)
echo "未知使用者"
esac
# 案例2:編寫nginx啟動指令碼
#!/bin/bash
# 需要實現Nginx的啟動、重啟、關閉等功能
read -p '請輸入:' status
. /etc/init.d/functions
case $status in
start)
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -ne 0 ];then
/usr/sbin/nginx -c /etc/nginx/nginx.conf
if [ $? -eq 0 ];then
action "Nginx啟動成功" /bin/true
else
action "Nginx啟動失敗" /bin/false
fi
else
action 'Nginx程序已經存在' /bin/true
fi
;;
stop)
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop
if [ $? -eq 0 ];then
action "Nginx關閉成功" /bin/true
else
action "Nginx關閉失敗" /bin/false
fi
;;
restart)
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s reopen
if [ $? -eq 0 ];then
action "Nginx重啟成功" /bin/true
else
action "Nginx重啟失敗" /bin/false
fi
;;
*)
echo "請選擇:start、stop或者restart"
ecas
知識儲備:
action命令是用來顯示執行結果格式的命令,預設系統不支援`action`,需要執行`. /etc/init.d/functions`命令才行
8、流程控制之while語句
8.1 while迴圈控制語句
語法:
while 條件
do
迴圈體
done
8.2 until迴圈控制語句
語法:
until 條件
do
迴圈體
done
8.3 while與until語句的區別
while 條件為true時迴圈;until 條件為false時迴圈。
8.5 迴圈中的break和continue
關鍵字 | 解釋 |
---|---|
break | 跳出本層迴圈 |
continue | 跳出本次迴圈 |
8.4 案例
# 案例:猜年齡
#!/bin/bash
old=18
while true
do
read -p '請輸入年齡:' num
if [ "$old" == "$num" ];then
echo "猜對了"
break
elif [ $old -gt $num ];then
echo "猜小了"
else
echo "猜大了"
fi
done
# 案例:測試break和continue
#!/bin/bash
while true
do
echo "第一層開始"
while true
do
sleep 1
echo "第二層開始"
break
echo "第二層結束"
done
echo "第一層結束"
sleep 1
done
# 案例:監控伺服器
#!/bin/bash
fails=0
while [ $fails -lt 3 ]
do
ping -c 1 -t 1 172.17.16.20 &>/bin/null
if [ $? -ne 0 ];then
let fails++
fi
done
echo "探測失敗 $fails 次"
[root@dxd ~]# ./first.sh
探測失敗 3 次
9、流程控制之for迴圈
語法:
# shell風格的語法
for 變數 in [取值列表]
do
迴圈體
done
# C語言風格的語法
for (( 初始值; 條件; 步長))
do
迴圈體
done
9.1 案例
# 案例:輸出10個數
#!/bin/bash
for i in {1..10}
do
echo $i
done
for (( i=1; i<=10; i++))
do
echo $i
done
# 案例:探測當前網段有哪些IP可用
#!/bin/bash
for i in {1..254}
do
ping -c 1 -W 1 172.17.16.$i &>/dev/null
if [ $? -eq 0 ];then
echo "172.17.16.$i 被佔用"
else
echo "172.17.16.$i 可用"
fi
done
# 案例:測試/root目錄中各種型別的檔案的個數
#!/bin/bash
file=0
dir=0
all=0
for i in `ls /root`
do
if [ -f /root/$i ];then
let file++
elif [ -d /root/$i ];then
let dir++
else
let all++
fi
done
echo " 普通檔案有 $file 個;普通資料夾有 $dir 個; 其他型別檔案有 $all 個"
10、流程控制之select語句
select表示式是bash的一種擴充套件應用,擅長於互動式場合。使用者可以從一組不同的值中進行選擇。
語法:
select 變數 in [值列表]
do
迴圈體
done
10.1 案例
# 案例:選擇你的愛好
#!/bin/bash
PS3='請選擇你的愛好:'
select i in '吃' '睡' '玩'
do
echo "你選擇的是 $i "
done
# 案例:編寫一個Nginx啟動指令碼,需要實現Nginx的啟動、重啟、關閉等功能
#!/bin/bash
. /etc/init.d/functions
PS3="請選擇操作Nginx的狀態:"
select status in start stop restart quit
do
if [ "$status" == "quit" ];then
break
fi
case $status in
start)
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -ne 0 ];then
/usr/sbin/nginx -c /etc/nginx/nginx.conf
if [ $? -eq 0 ];then
action "Nginx啟動成功" /bin/true
else
action "Nginx啟動失敗" /bin/false
fi
else
action 'Nginx程序已經存在' /bin/true
fi
;;
stop)
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop
if [ $? -eq 0 ];then
action "Nginx關閉成功" /bin/true
else
action "Nginx關閉失敗" /bin/false
fi
;;
restart)
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s reopen
if [ $? -eq 0 ];then
action "Nginx重啟成功" /bin/true
else
action "Nginx重啟失敗" /bin/false
fi
;;
*
echo "請選擇:start、stop或者restart"
esac
done
11、函式
# 什麼是函式?
函式就是用來盛放一組程式碼的容器,函式內的一組程式碼一定具備某種特定的功能,稱之為一組程式碼塊。
呼叫函式便可以觸發函式內的程式碼塊。這個過程可以實現程式碼的複用。
# 為什麼要用函式?
1、為了減少程式碼冗餘
2、提升程式碼的組織結構性、可讀性
3、增強拓展性
# 函式必須遵守的原則?
先定義,後呼叫。
11.1 函式的語法
# 語法一:推薦使用
function [函式名稱] () {
函式體
}
# 語法二:
function 函式名 {
函式體
}
# 語法三:
函式名 {
函式體
}
11.2 案例
# 案例:計算1+1=2
#!/bin/bash
function add() {
let n=1+1
echo $n
}
function add1 {
let n=1+1
echo $n
}
add2 {
let n=1+1
echo $n
}
11.3 呼叫函式
11.3.1 有引數函式
# 直接在函式名之後傳入即可。
[root@dxd ~]# ./first.sh
2
[root@dxd ~]# vim first.sh
#!/bin/bash
function add() {
let n=$1+$2
echo $n
}
add 1 2
11.3.2 無引數函式
[root@dxd ~]# ./first.sh
2
[root@dxd ~]# vim ./first.sh
#!/bin/bash
function add() {
let n=1+1
echo $n
}
add
11.4 案例
# 案例:實現一個簡單的計算器
#!/bin/bash
function j() {
let n=$1+$2
echo $n
}
function ja() {
let n=$1-$2
echo $n
}
function c() {
let n=$1*$2
echo $n
}
function cu() {
let n=$1/$2
echo $n
}
PS3="請選擇計算模式:"
select i in + - x /
do
case $i in
+)
j $1 $2
break
;;
-)
ja $1 $2
break
;;
x)
c $1 $2
break
;;
/)
cu $1 $2
break
;;
*)
echo "error"
esac
done
# 案例:實現Nginx指令碼
#!/bin/bash
. /etc/init.d/functions
function start() {
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ];then
action "Nginx程序已存在" /bin/true
else
/usr/sbin/nginx -c /etc/nginx/nginx.conf
if [ $? -eq 0 ];then
action "Nginx啟動成功" /bin/true
else
action "Nginx啟動失敗" /bin/false
fi
fi
}
function stop() {
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ];then
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop
if [ $? -eq 0 ];then
action "Nginx關閉成功" /bin/true
else
action "Nginx關閉失敗" /bin/false
fi
else
action "Nginx未啟動" /bin/false
fi
}
function restart() {
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ];then
stop
start
else
start
fi
}
PS3="請選擇Nginx操作模式:"
select i in start stop restart quit
do
case $i in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
quit)
break 2
;;
*)
echo "請選擇:start、stop或者restart"
esac
done
11.5 返回值(return)
# 函式中的返回值一般是[0 ~ 128]
#!/bin/bash
. /etc/init.d/functions
function start() {
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ];then
action "Nginx程序已存在" /bin/true
else
/usr/sbin/nginx -c /etc/nginx/nginx.conf
if [ $? -eq 0 ];then
action "Nginx啟動成功" /bin/true
else
action "Nginx啟動失敗" /bin/false
return 1
fi
fi
return 0
}
function stop() {
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ];then
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop
if [ $? -eq 0 ];then
action "Nginx關閉成功" /bin/true
else
action "Nginx關閉失敗" /bin/false
return 1
fi
else
action "Nginx未啟動" /bin/false
fi
return 0
}
function restart() {
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ];then
stop && start
[ $? -eq 0 ] && return 0 || return 1
else
start
[ $? -eq 0 ] && return 0 || return 1
fi
}
PS3="請選擇Nginx操作模式:"
select i in start stop restart quit
do
case $i in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
quit)
break 2
;;
*)
echo "請選擇:start、stop或者restart"
esac
done
12、陣列
# 陣列分類
1、普通陣列
2、關聯陣列
# 為什麼要用陣列?
將具有相同屬性的一組元素集合到一起,避免單獨定義麻煩。
12.1 陣列的定義
# 普通陣列的定義方式
declare -a array=(1 2 3 4 5 6 7 8 9)
# 關聯陣列的定義方式
declare -A array1=([name]=shanhe)
12.2 陣列的訪問
普通陣列:正向索引從0開始,反向索引從-1開始。
關聯陣列:按照下標。
12.4 遍歷陣列
# 知識儲備:
取所有值:${array[*]}
取所有鍵:${!array1[*]}
12.4.1 遍歷普通陣列
#!/bin/bash
declare -a array=(1 2 3 4 5 6 7 8 9)
for i in ${array[*]}
do
echo $i
done
12.4.2 遍歷關聯陣列
[root@dxd ~]# for i in ${!array1[*]};
do
echo ${array1[$i]};
done
[root@dxd ~]# for i in ${array1[*]}
do
echo $i
done
12.4.3 案例
# 案例:通過陣列判斷當前資料夾中的各種檔案型別的個數
[root@dxd ~]# cat first2.sh
#!/bin/bash
declare -a array=(`ls`)
dir=0
file=0
for i in ${array[*]}
do
[ -d $i ] && let dir++
[ -f $i ] && let file++
done
echo "普通檔案有:$file 個,普通資料夾有:$dir 個。"
13、訊號處理
13.1 HUP(1)訊號
13.1.1 掛起
[root@dxd ~]# cat first3.sh
#!/bin/bash
echo $$
sleep 1000
[root@dxd ~]# kill -1 1993
13.1.2 重新載入配置
[root@dxd ~]# kill -s HUP 2277
等價
[root@dxd ~]# kill -1 2277
13.2 退出訊號
- INT(2):由ctrl + c 發出的訊號。
- QUIT(3):由 ctrl + \ 發出的訊號。
- TSTP(20):由 ctrl + z 發出的訊號。
# 知識儲備:trap
#!/bin/bash
# 捕捉 ctrl + c 訊號
trap "echo 已經捕捉到 ctrl + c訊號"
sleep 1000
13.3 終止訊號
- KILL(9):殺死訊號
立即回收記憶體。
- TERM(15):停止訊號
先通知程序終止,超時未終止的訊號再殺死。
14、Systemctl管理指令碼
systemctl配置檔案路徑:/usr/lib/systemd/system
14.1 systemctl包含的檔案
*.service:操作服務檔案
*.target:開機級別的服務檔案
14.2 systemctl配置的格式
unit:主要是用來做服務說明的(沒有實際意義)。
service:核心區域(各種服務操作【開啟、停止、重啟等】)
install:用來配置多使用者
14.3 unit
Description:主要是用來簡介。
After:表示該服務需要在那些服務後啟動。
Before:表示在某些服務之前啟動。
14.4 Service
- Type:表示在後臺執行的模式
- User:表示服務執行的使用者,預設:當前使用者
- Group:表示執行的使用者組,預設:當前使用者
- PIDFile:指定PID檔案路徑
- ExecStart:指定服務的啟動命令
- ExecReload:指定服務重啟時執行的命令
- ExecStop:指定服務停止執行的命令,預設執行 kill -s TERM
- PrivateTmp:指定是否分配臨時的獨立空間
- Environment:指定環境變數的
- ExecStartPre:啟動服務之前執行的命令
- ExecStartPost:服務啟動之後執行的命令
- ExecStopPost:服務停止之後執行的命令
14.5 Install
# WantedBy=multi-user.target # 定支援多使用者模式
[root@dxd system]# cat nginx2.service
[Unit]
Description=Nginx Service 測試服務檔案
After=network.target
Before=mysqld.service
[Service]
Type=foking
User=root
Group=root
PIDFile=/run/nginx2.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStopPost=echo "Stop Success"
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/usr/bin/kill -s HUP $MAINPID
ExecStop=/usr/bin/kill -s TERM $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
14.6 Type型別
- forking:需要被啟動的程序擁有主程序和子程序。
- simple:啟動命令產生程序就是主程序
- notify:類似於simple
# 通常情況下,在後臺執行的命令使用forking;在前臺執行的命令使用simple和notify等。
14.7 重啟型別(Restart)
- on:一旦程式出現宕機,system不做任何管理 (預設)
- on-success:只有正常退出情況下,才會重啟。
- on-failure:非正常退出時,重啟
- on-abnaomal:只有訊號終止或超時,才會重啟
- always:不管什麼原因退出,都會重啟
# 通常情況下,採用on或者on-success兩個引數。
14.8 案例:啟動Nginx
[root@dxd ~]# vim nginx.sh
#!/bin/bash
. /etc/init.d/functions
args=$1
function print() {
[ $? -eq 0 ] && action "Nginx $args is " /bin/true || action "Nginx $args is " /bin/false
}
case $args in
start)
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -ne 0 ]; then
/usr/sbin/nginx -c /etc/nginx/nginx.conf
fi
print
;;
stop)
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ]; then
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop
fi
print
;;
restart)
netstat -nutlp | grep 'nginx: master' &>/dev/null
if [ $? -eq 0 ]; then
/usr/sbin/nginx -c /etc/nginx/nginx.conf -s stop
sleep 1
fi
/usr/sbin/nginx -c /etc/nginx/nginx.conf
print
;;
test)
/usr/sbin/nginx -c /etc/nginx/nginx.conf -t
print
;;
*)
echo "Please Enter start/stop/test/restart"
;;
esac
# Service
[root@dxd ~]# vim /usr/lib/systemd/system/nginx3.service
[Unit]
Description=Nginx Service 指令碼服務檔案
[Service]
Type=forking
ExecStartPre=/usr/local/bin/nginx.sh test
ExecStart=/usr/local/bin/nginx.sh start
ExecReload=/usr/local/bin/nginx.sh restart
ExecStop=/usr/local/bin/nginx.sh stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target