文章目錄
- 一、Shell腳本語言的基本結構
- 1、Shell腳本的用途:
- 2、 Shell腳本基本結構:
- 3、 創建Shell腳本過程
- 4、 腳本注釋規范
- 二、Shell腳本語言的變量用法詳解
- 位置與預定義變量
- 三、 Shell字符串詳解
- 1、Shell字符串拼接
- 2、Shell字符串截取
- 3、 Shell的格式化輸出printf
- 4、條件測試命令
- 5、條件測試命令及其語法
- 6、文件測試表達式
- 7、整數測試表達式
- 8、關于()與 { }
- 9、使用read命令命令來接受輸入
- 四、流程控制
- 4.1 條件選擇
- 4.1.1 選擇執行if語句
- 4.1.1.1 單分支
- 4.1.1.2 雙分支
- 4.1.1.3 多分支
- 4.1.2條件判斷case語句
- 4.2、循環
- 4.2.1、循環執行介紹
- 4.2.2、for循環
- 4.2.3、while循環
- 4.2.4、循環控制語句continue 、break
- 4.3、Shell中的數組
- 4.3.1、Shell數組的概念
- 4.3.2、Shell數組的定義
- 4.3.3、數組的基本定義
- 4.3.4、Shell數組的拼接合并
- 4.3.5、Shell刪除數組元素
- 4.3.6、獲取數組某范圍的元素
- 5、Shell中的函數
- 5.1、Shell函數的定義
- 6、Shell編程之正則表達式
- 6.1、正則表達式
- 6.1.1、正則表達式概述
- 6.1.2、正則表達式的分類
- 五、shall實戰
- 打印99乘法表
- 直角三角形
- 創建用戶
- 猜數游戲
一、Shell腳本語言的基本結構
1、Shell腳本的用途:
- 自動化常用命令
- 執行系統管理和故障排除
- 創建簡單的應用程序
- 處理文本或文件
2、 Shell腳本基本結構:
Shell腳本編程:是基于過程式,解釋執行的語言
編程語言的基本結構:
- 各種系統命令的組合
- 數據存儲:變量,數組
- 表達式:a+b
- 控制語句:if、case、for、while
shell腳本:包含一些命令或聲明,并符合一定格式的文本文件
格式要求:首行執行shebang機制
#聲明后續語句是通過那種語言寫的
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
3、 創建Shell腳本過程
- 使用vim創建文本文件,第一行必須包括shell聲明序列:
#!/bin/bash
- 加執行權限,給予執行權限,在命令行上指定腳本的絕對或相對路徑
[root@localhost ~]# chmod +x shellScript/hello.sh
- 運行腳本,直接運行解釋器,將腳本作為解釋器程序的參數運行。
[root@localhost ~]# /root/shellScript/hello.sh
4、 腳本注釋規范
- 第一行一般為調用使用的語言
- 程序名,避免更改文件名為無法找到正確的文件
- 版本號
- 更改后的時間
- 作者相關信息
- 該程序的作用,及注意事項
- 最后是各版本的更新簡要說明
二、Shell腳本語言的變量用法詳解
位置與預定義變量
位置變量:在Bash Shell中內置的變量,在腳本代碼中調用命令行傳遞給腳本的參數
$1,$2,... 對應第一個,第二個等參數,shift[n]換位置,最多9個
#預定義變量
$0 命令本身,包括路徑
$* 傳遞給腳本的所有參數,全部參數合成一個字符串
$@ 傳遞給腳本的所有參數,每個參數為獨立字符串
$# 傳遞給腳本的參數的個數
$? 上個命令的退出狀態,或函數的返回值
$$ 當前shell進程ID。對于Shell腳本,就是這些腳本所在的進程ID注意:$@,$*只有被雙引號括起來的時候才會有差異
三、 Shell字符串詳解
字符串(String)就是一系列字符的組合。字符串是Shell編程中最常用的數據類型之一
字符串可以由單引號''
包圍,也可以由""
包圍,也可以不用引號,三種方式的區別
- 由單引號
' '
包圍的字符串- 任何字符都會原樣輸出,在其中使用變量是無效的
- 字符串中不能出現單引號,即使對單引號進行轉義也不行
- 由雙引號
" "
包圍的字符串- 如果其中包含了某個變量,那么該變量就會被解析(得到該變量的值),而不是原樣輸出
- 字符串中可以出現雙引號,只要進行轉義就行
- 不被引號包圍的字符串
- 不被引號包圍的字符串中出現變量也會被解析,這一點和雙引號
""
包圍的字符串一樣 - 字符串中不能出現空格,否則空格后面的字符串會作為其他變量或者命令解析
獲取字符串長度
- 不被引號包圍的字符串中出現變量也會被解析,這一點和雙引號
在Shell中獲取字符串長度很簡單,具體方法如下:
${#string_name}
string_name:表示字符串名字
1、Shell字符串拼接
在腳本語言中,字符串的拼接(也稱為字符串連接或者字符串合并)往往都非常簡單,在Shell中你不需要使用任何運算符,將兩個字符串并排放在一起就能實現拼接
2、Shell字符串截取
Shell截取字符串通常有兩種方式,從指定位置開始截取和從指定字符(子字符串)開始截取
從指定位置開始截取
這種方式需要兩個參數:除了指定起始位置,還需要截取長度,才能最終確定要截取的字符串
既然需要指定起始位置,那么就要涉及到計數方向的問題,到底是從字符串左邊開始計數,還是從字符串右邊開始計數?答案是:Shell同時支持兩種計數方式
1.從字符串左邊開始計數
如果想從字符串的左邊開始計數,那么截取字符串的具體格式如下:
${string:start:length}其中,Sting是要截取的字符串,start是起始位置(從左邊開始,從0開始計數),length是要截取的長度(省略的話表示直到字符串的末尾)
例如:
url="c.biancheng.net"
echo ${url:2:9}>結果為:bianchengurl="c.biancheng.net"
echo ${url:2} #省略length,截取到字符串末尾>結果為:biancheng.net
2.從右邊開始計數
如果想從字符串的右邊開始計數,那么截取字符串的具體格式如下:
格式:
${string:0-start:length}
實例
url="c.biancheng.net"
echo ${url:0-13:9}>結果為:biancheng 從右邊數:b是第13個字符url="c.biancheng.net"
echo ${url:0-13} #省略length,直接截取到字符串末尾
>結果為:biancheng.net
3、 Shell的格式化輸出printf
%f浮點格式,保留小數點位數%.nf,n為數字**
常用轉義字符:
轉義符 | 功能 |
---|---|
\a | 警告字符,通常為ASCII的BEL字符 |
\b | 后退 |
\f | 換頁 |
\n | 換行 |
\r | 回車 |
\t | 水平制表符 |
\v | 垂直制表符 |
\\ | 表示\本身 |
實現算數運算
1. let var=算術表達式
2. var=$[算術表達式]
3. var=$((算術表達式))
4. var=$(expr arg1 arg2 arg3 ...)
5. declare -i var = 數值
6. echo '算術表達式' | bc (支持浮點數)
**內建的隨機數生成器變量:
$RANDOM 取值范圍:0-32767
4、條件測試命令
條件測試:判斷某需求是否滿足,需要由測試機制來實現,專用的測試表達式需要由測試命令輔助完成測試過程,實現評估布爾聲明,以便在條件性環境下進行執行。
- 若真,則狀態碼變量$?返回0
- 若假,則狀態碼變量$?返回1
5、條件測試命令及其語法
語法1:test <測試表達式> 說明:test命令和<測試表達式>之間至少有一個空格
在shell中,大于用 -gt 表示,小于用 -lt 表示,大于或等于用 -ge 表示,小于或等于用 -le表示 ,不相等用-ne 表示
[root@ansible-salve1 ~]# test 1 -lt 2
[root@ansible-salve1 ~]# echo $?
0
[root@ansible-salve1 ~]# test 2 -lt 1
[root@ansible-salve1 ~]# echo $?
1
[root@ansible-salve1 ~]#
6、文件測試表達式
常用的文件測試操作符 | 說明 |
---|---|
-a/-e 文件 | 文件是否存在 |
-d 文件 | 文件存在且為目錄則為真,即測試表達式成立 |
-f 文件 | 文件存在且為普通文件則為真,即測試表達式成立 |
-r 文件 | 文件存在且可讀為真 |
-w 文件 | 文件存在且可寫為真 |
-x 文件 | 文件存在且可執行則為真 |
-z字符串若字符串的長度為0,則為真,z可以理解為zero
“字符串1” == ”字符串2“若字符串1長度等于字符串2長度,則為真
“字符串1” != ”字符串2“若字符串1長度不等于字符串2長度,則為真
“字符串1” =~ “字符串2”左側字符串是否能被右側的PATTERN所匹配。
7、整數測試表達式
在[ ] 或 test中使用的比較符號 | 在(()) 或 [[ ]]中使用的比較符號(不用這個做數字比較) | 說明 |
---|---|---|
-eq | == 或 = | 相等,equal |
-ne | != | 不相等,not equal |
-gt | > | 大于,greater than |
-ge | > = | 大于等于,greater equal |
-lt | < | 小于,less than |
-le | < = | 小于等于,less equal |
8、關于()與 { }
( )和 { }都可以將多個命令組合再一次,批量執行,{ } 里的內容需要與兩側用空格隔開并在命令結尾加上;
- ( )會開啟子shell,并且list中變量賦值及內部命令執行后,將不再影響后續的環境
9、使用read命令命令來接受輸入
read 是 Shell 內置命令,用來從標準輸入中讀取數據并賦值給變量。如果沒有進行重定向,默認就是從鍵盤讀取用戶輸入的數據;如果進行了重定向,那么可以從文件中讀取數據
選項:
Option | 說明 |
---|---|
-a array | 把讀取的數據賦值給數組array,從下標0開始 |
-d delimiter | 把字符串delimiter指定讀取結束的位置,而不是一個換行符(讀取的數據不包括delimiter) |
-e | 在獲取用戶輸入的時候,對功能鍵進行編碼轉換,不會直接顯示功能鍵對應的字符 |
-n num | 讀取num個字符,而不是整行字符 |
-p prompt | 顯示提示信息,提示內容為prompt |
-r | 原樣讀取(Raw mode),不會把反斜杠字符解釋為轉義字符 |
-s | 靜默模式(Silent mode),不會再屏幕上顯示輸入的字符。例如:輸入密碼 |
-t seconds | 設置超時時間,單位為秒。如果用戶沒能按時完成,返回一個非0的退出狀態 |
-u fd | 使用文件描述符fd作為輸入源,而不是標準輸入,類似于重定向 |
四、流程控制
4.1 條件選擇
4.1.1 選擇執行if語句
if結構:
[root@ansible-salve1 shell]# help if
if: if 條件; then 命令; [ elif 命令; then 命令; ]... [ else 命令; ] fi根據條件執行命令。`if COMMANDS'列表被執行。如果退出狀態為零,則執行`then COMMANDS' 列表。否則按順序執行每個 `elif COMMANDS'列表,并且如果它的退出狀態為零,則執行對應的 `then COMMANDS' 列表并且 if 命令終止。否則如果存在的情況下,執行 `else COMMANDS'列表。整個結構的退出狀態是最后一個執行的命令的狀態,或者如果沒有條件測試為真的話,為零。退出狀態:返回最后一個執行的命令的狀態。
[root@ansible-salve1 shell]#
4.1.1.1 單分支
if [ 條件判斷式 ];then命令
fi 或者if [ 條件判斷式 ]then命令
fi
4.1.1.2 雙分支
if [ 條件判斷式 ]then命令
else命令
fi
4.1.1.3 多分支
if [ 條件判斷式1 ]then命令
elif [ 條件判斷式2 ]then 命令
...
...
else命令
fi
說明:
- 多個if條件時,逐個條件進行判斷,第一次遇見為“真”條件時,執行其分支,而后結束整個if語句
- if語句可嵌套
4.1.2條件判斷case語句
格式
case 變量引用 in
PAT1)分支1;;
PAT2)分支2;;
...
*)默認分支;;
esac
實例:
#!/bin/bash
cat <<EOF
請選擇:
1.備份文件
2.清理日志文件
3.軟件升級
4.軟件回滾
5.刪庫跑路
EOF
read -p "請輸入上面的數字1-5:" MENU
case $MENU in
1)./backup.sh;;
2)echo "清理日志";;
3)echo "軟件升級";;
4)echo "軟件回滾";;
5)echo "刪庫跑路";;
*)echo "Input False"
esac
[root@bogon ~]# bash 1.sh
請選擇:
1.備份數據庫
2.清理日志文件
3.軟件升級
4.軟件回滾
5.刪庫跑路
請輸入上面的數字1-5:1
備份成功
4.2、循環
4.2.1、循環執行介紹
將某代碼段重復運行多次,通常有進入循環的條件和退出循環的條件
重復運行次數
- 循環次數事先已知
- 循環次數事先未知
常見的循環的命令:for,while
#循環的邏輯:程序先進行語句判斷,如果為真則執行循環語句,然后再進行語句判斷,直至語句判斷失敗才跳出
4.2.2、for循環
格式:
第一種寫法
for NAME [in words ...]; do commands;done# 第二種寫法
for 變量 in 列表循環體
done# 第三種寫法
for 變量 in 列表
do循環體
done
4.2.3、while循環
while command; do commands;donewhile condition;do 循環體 done
無限循環
while true;do循環體
done
4.2.4、循環控制語句continue 、break
continue\[N\]:提前結束第N層的本輪循環,而直接進入下一輪判斷;最內層為第1層格式:while CONDITION1;do循環體1...if command2;thencontinuefiCMDn....
done
break\[N\]:提前結束第N層后的全部循環;最內層為第1層,默認為1#!/bin/bash
for((i=0;i<10;i++));dofor((j=0;j<10;j++));do[ $j -eq 5 ] && breakecho $j doneecho ----------------------------done
4.3、Shell中的數組
4.3.1、Shell數組的概念
數組是若干數據的集合,其中存放的每一份數據都稱為元素。Shell
不限制數組的大小,理論上可以存放無限量的數據,Shell
數組元素的下標也是從0開始計數
獲取數組中的元素要使用下標[ ],下標可以是一個整數,也可以是一個結果為整數的表達式;下標必須大于等于0
注意:
Shell
只支持一維數組,不支持多維數組
4.3.2、Shell數組的定義
4.3.3、數組的基本定義
在Shell
中,用小括號()
來表示數組,數組元素之間用空格來分隔
#arrayname=(1 2 3 4 5)
`輸出定義數組中的全部元素
#echo ${arrayname[*]}
#echo ${arrayname[@]}
`輸出定義數組中的第二個元素
#echo ${arrayname[0]}
`輸出定義數組中的第二個元素
#echo ${arrayname[1]}
`輸出定義數組中的元素個數
#echo ${#arrayname[*]}
4.3.4、Shell數組的拼接合并
array_new=(${array1[@]} ${array2[@]})
array_new=(${array1[*]} ${array2[*]})
`兩種方式是等價的,選擇其一即可。其中,array1 和 array2 是需要拼接的數組,array_new 是拼接后形成的新數組。
4.3.5、Shell刪除數組元素
unset array_name[index]
`其中,array_name表示數組名,index表示數組下標unset array_name
`刪除整個數組
4.3.6、獲取數組某范圍的元素
在Shell
中直接通過${數組名[@/*]:起始位置:長度}
獲取數組給定范圍內元素,返回字符串,中間用空格分開
#!/bin/bash
array=(yoona lucy tom)
echo ${array[*]}
echo ${array[*]:1:2}
echo ${array[@]:0:2}
-->結果為:
yoona lucy tom
lucy tom
yoona lucy
5、Shell中的函數
5.1、Shell函數的定義
Shell函數的本質是一段可以重復使用的腳本代碼,這段代碼被提前編好了,放在了指定位置,使用時直接調用即可
Shell 中的函數和C++、Java、Python、C# 等其它編程語言中的函數類似,只是在語法細節有所差別。
Shell 函數定義的語法格式如下:
function name() {statements[return value]
}
對各個部分的說明:
function
是 Shell 中的關鍵字,專門用來定義函數;name
是函數名;statements
是函數要執行的代碼,也就是一組語句;return value
表示函數的返回值,其中 return 是 Shell 關鍵字,專門用在函數中返回一個值;這一部分可以寫也可以不寫。
由{ }
包圍的部分稱為函數體,調用一個函數,實際上就是執行函數體中的代碼。
6、Shell編程之正則表達式
6.1、正則表達式
6.1.1、正則表達式概述
正則表達式通常用于判斷語句中,用來檢查某一字符串是否滿足某一格式。
正則表達式是由普通字符與元字符組成。普通字符包括小寫字母、數字、標點符號及一些其他符號。元字符是指在正則表達式中具有特殊意義的專用字符,可以用來規定其前導字符(即位于元字符前面的字符)在目標對象中的出現模式。
6.1.2、正則表達式的分類
正則表達式根據從POSIX BRE或者POSIX ERE標準可以分為基本正則表達式和擴展正則表達式。
基本正則表達式
支持的工具:grep
、egrep
、sed
、 awk
,注意grep
要配合-E
或者-P
使用。
元字符 | 含義及用法 |
---|---|
\ | 轉義字符,用于取消特殊符號的含義,例: \! 、 \n 、 \$ 等 |
^ | 匹配字符串開始的位置,例:^a 、^the 、^# 、^[a-z] |
$ | 匹配字符串結束的位置,例: word$ 、^$ 匹配空行 |
. | 匹配除\n 之外的任意的一個字符,例: go.d 、g..d 。如果想要匹配包含\n字符可以使用 [.\n] |
* | 匹配前面子表達式0次或者多次,例: goo*d 、 go.*d |
[list] | 匹配list列表中的一個字符,例: go[ola]d ,[abc] 、[a-z] 、[a-z0-9] 、[0-9] 匹配任意一位數字 |
[^list] | 匹配任意非list列表中的一個字符,例:[^0-9] 、[^A-Z0-9] 、[^a-z] 匹配任意一位非小寫字母 |
\{n\} | 匹配前面的子表達式n次,例: go\{2\}d 、 [0-9]\{2\} 匹配兩位數字 |
\{n,\} | 匹配前面的子表達式不少于n次,例: gol{2,l}d 、[0-9]\{2,\} 匹配兩位及兩位以上數字 |
\{n,m\} | 匹配前面的子表達式n到m次,例 : go\{2,3\}d 、[0-9]\{2,3\} 匹配兩位到三位數字 |
注: egrep 、 awk 使用{n} 、{n,} 、{n,m} 匹配時 {} 前不用加 \ | |
\w | 匹配包括下劃線的任何單詞字符。 |
\W | 匹配任何非單詞字符。等價于[^A-Za-z0-9_] 。 |
\d | 匹配一個數字字符。 |
\D | 匹配一個非數字字符。等價于[^0-9] 。 |
\s | 空白符。 |
\S | 非空白符。 |
擴展正則表達式
支持的工具:egrep
、awk
,注意:使用grep
要配合-E
或者-P
使用,sed
要配合-r
使用。
五、shall實戰
打印99乘法表
#!/bin/bash
for i in {1..9};dofor j in `seq $i`;doecho -e "${j}x$i=$((j*i))\t\c "doneecho
done
結果
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
方法2
#!/bin/bash
for((i=1;i<10;i++))
dofor ((j=1;j<=i;j++)) ;doecho -e "$j×$i=$((j*i))\t\c"done
echo
done
輸出結果一樣
直角三角形
[root@localhost ~]# bash 99.sh
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
[root@localhost ~]# cat 99.sh
#!/bin/bash
for((i=1;i<10;i++))
dofor ((j=1;j<=i;j++)) ;doecho -e "*\t\c"done
echo
done
創建用戶
read -p "請輸入你創建的用戶名:" name
test -d /home/$name
if [ $? -eq 0 ];
thenecho "用戶已存在"exit 0;
elseecho "正在創建用戶..."useradd $nameecho 123.com | passwd --stdin $nameecho "已經創建用戶$name,初始密碼為123.com"exit 1;
fi
猜數游戲
#!/bin/bash
# 腳本生成一個100以內得隨機數,提示用戶猜數字,根據用戶得輸入,提示用戶猜小了或猜大了,直至用戶猜對腳本結束
# RANDOM為系統自帶的系統變量,值為0~32767的隨機數
# 使用取余算法將隨機數變為1~100的隨機數
num=$[RANDOM%100+1]
echo $num# 使用read 提示用戶猜數字
# 使用if判斷用戶猜數字的大小關系:
# -eq(等于),-ne(不等于),-gt(大于),-ge(大于等于),-lt(小于),-le(小于等于)
while :
do read -p "數字炸彈在1~100的隨機數,請選擇數字:" nif [ $n -eq $num ];thenecho "恭喜,爆炸了"exitelif [ $n -gt $num ];thenecho "你猜大了,縮小范圍為:0~$n之中"elseecho "你猜小了,縮小范圍為$n~100之中"fi
done