腳本編程(一) 啰里啰唆:每周的最後一天都特別難受。墨跡扣不出文章。 一、概況 註釋是以#開都的,#開頭不一定都是註釋 SHELL是解釋型語言 SHELL腳本第一句以#!/bin/bash開頭 SHELL腳本需要具有執行許可權 一般以.sh結尾 別名在腳本中無效。在腳本中不能使用別名。 bash使用技 ...
腳本編程(一)
啰里啰唆:每周的最後一天都特別難受。墨跡扣不出文章。
一、概況
註釋是以#開都的,#開頭不一定都是註釋
SHELL是解釋型語言
SHELL腳本第一句以#!/bin/bash開頭
SHELL腳本需要具有執行許可權
一般以.sh結尾
別名在腳本中無效。在腳本中不能使用別名。
bash使用技巧:
-n 檢查語法,無法無法檢測處命令錯誤,同時只是檢查語法不會真正執行腳本。
-x 逐行執行,逐行顯示執行結果
腳本中的錯誤:
1、語法錯誤,會導致後續的命令無法繼續執行。可以通過bash -n選項來檢查
提示的錯誤行不一定是準確的。
2、命令錯誤,後續的命令還可以繼續執行。無法通過bash -n 選項來檢查錯誤,可以使用set -e或者set -o errexit來設定遇到錯誤命令後退出
3、邏輯錯誤,只能使用bash -x選項來檢查錯誤。
變數:
變數表示命名的記憶體空間,講數據放在記憶體空間中,通過 "$變數名" 引用,從而獲取數據
內置環境變數:
PS1 SHELL HASTNAME $$ $?
自定義變數:
[set] NAME=VALUE set可以省略
變數類型:
字元型:預設都是字元型
數值:整型、 bash不支持浮點型
靜態編譯語言,使用變數前,先聲明變數類型,之後類型不能改變,在編譯時執行檢查,JAVA C
動態編譯語言:不用事先聲明,可以隨時改變變數類型,SHELL PYTHON
強類型語言:不同類型的操作數,必須經過強制轉換成同一類型的變數後才能運算
弱類型語言:不同類型的操作數,會隱式轉換數據類型,如SHELL
shell中變數命令規則
變數名不用實現聲明
變數名不能和系統已經定義好的變數同名
變數名不能和系統的內外部命令同名
變數名不能和系統定義好的關鍵字同名,如:if else case for 等
變數名不能以數字開頭
變數名不支持短橫線-
變數名需要見名知意,最好用英語名,最好不要命拼音,不要用拼英縮寫
統一命名規則:駝峰命名法,大駝峰studentName 小駝峰studentName
變數名大寫
局部變數小寫
函數名小寫
普通變數,生效範圍是當前shell進程;對當前shell之外的其它進程(包括當前shell的子進程)均無效。
環境變數,生效範圍是當前shell進程及其子進程
本地變數,生效範圍進士當前shell進程中某個代碼片段,通常指函數。
變數賦值的時候等號左右不要有空格: NAME="value" 如果賦值中有空格需要使用引號引起來。
可以把文件路徑賦值給變數。
特殊用法參考以下示例:
[root@CentOS8 /]# FILE=/* [root@CentOS8 /]# echo $FILE /bin /boot /data /dev /etc /home /lib /lib64 /media /mnt /opt /proc /root /run /sbin /srv /sys /@System.solv /tmp /usr /var /* [root@CentOS8 /]# ls -d $FILE /bin /data /etc /lib /media /opt /root /sbin /sys /tmp /var /boot /dev /home /lib64 /mnt /proc /run /srv /@System.solv /usr [root@CentOS8 /]# ls -d "$FILE"
變數引用 $NAME ${NAME}
變數引用的時候,加上雙引號會保留原始的回車符等隱式字元,
不加上雙引號預設會去掉回車符並以空格代替。
看以下示例 {
[root@CentOS8 ~]# NUM=`seq 10` [root@CentOS8 ~]# echo "$NUM" 1 2 3 4 5 6 7 8 9 10 [root@CentOS8 ~]# echo $NUM 1 2 3 4 5 6 7 8 9 10 [root@CentOS8 ~]#
註意:變數賦值時臨時生效,當退出終端後,變數會自動刪除;腳本中的變數會隨著腳本結束自動刪除。
env可以顯示所有已經定義好的環境變數
export不跟任何選項,也可以顯示所有已經定義的環境變數
declare -x 也可以顯示所有已經定義的環境變數
set可以顯示所有已經定義好的所有變數
unset NAME可以取消變數定義
unset NAME1 NAME2 NAME3...取消多個變數
無法在子shell中使用父shell中定義的本地變數,可以使用export或declare -x把變數聲明成環境變數,就可以在子shell(包括孫子進程)中調用父shell中定義的環境變數。但是無法讓父進程繼承子進程的
變數,孫子進程可以繼承子進程的環境變數。
$BASHPID 顯示當前進程的PID
$PPID 顯示父進程的PID
LANG 語言系環境變數
MAIL 郵箱
SHLVL shell的嵌套深度
變數除了可以存字元,還可以存命令。$CMD的結果SHELL會當成命令執行。
只讀變數,定義後的只讀變數不能修改和刪除,只能退出重新登
readonly NAME 定義只讀變數
declare -r NAME 定義只讀變數
位置變數:
$0 表示命令本身,會包括路徑
$1 表示對應第一個參數,使用shift n替換
$2 表示對應第二個參數,使用shift n替換
...
${10} 表示對應的第十個參數,不能直接寫成$10
${11} 表示對應的第十一個參數,不能直接寫成$11
$* 表示所有參數,會把各個變數看成統一整體,只有雙引號”$*"”$@"才有區別
$@ 表示所有參數,會把各個變數看成獨立個體,只有雙引號”$*"”$@"才有區別
$# 表示參數個數
$? 判斷上一條執行狀態的執行結果
$_ 前一個命令的最後一個參數
set -- 清楚所有位置變數
[root@CentOS7 2]# cat arg.sh #!/bin/bash # echo "1st is $1" echo "2st is $2" echo "3st is $3" echo "10st is ${10}" echo "10st is $10" echo "11st is ${11}" echo "11st is $11" echo "The number of `basename $0` is $#" echo "All args are $*" echo "All args are $@"
./arg2.sh $* ;echo '$*' ./arg2.sh $@ ;echo '$@' ./arg2.sh "$*" ;echo '"$*"' ./arg2.sh "$@" ;echo '"$@"'
[root@CentOS7 2]# cat arg2.sh #!/bin/bash # echo -n "$1 " [root@CentOS7 2]# ./arg.sh {a..z} 1st is a 2st is b 3st is c 10st is j 10st is a0 11st is k 11st is a1 The number of arg.sh is 26 All args are a b c d e f g h i j k l m n o p q r s t u v w x y z All args are a b c d e f g h i j k l m n o p q r s t u v w x y z a $* a $@ a b c d e f g h i j k l m n o p q r s t u v w x y z "$*" a "$@" [root@CentOS7 2]#
命令行展開
命令行展開優先順序
1、把命令行分成單個命令詞
2、展開別名
3、展開大括弧的聲明{}
4、展開波浪線聲明~
5、命令替換$()或··
6、再次把命令行分成命令詞
7、展開文件通配符
8、準備I/O重定向
9、運行命令
防止擴展
使用反斜線\會是隨後的字元按願意執行
腳本安全和set
she命令,地址shell環境
$- 以關鍵字形式顯示系統啟用功能
+表示禁用,-表示啟用
h 表示hash,可以set +h選項關閉hash
i 互動式,說明當前shell是個交互是shell
m 表示啟用job control來控制進程的停止
B 表示啟用大括弧擴展
H HISTORY,表示可以展開命令歷史列表
$_ 前一個命令的最後一個參數
set命令 修改環境變數
-o 打開關閉某些選項,如果後面不跟任何選項表示顯示以shell啟用的某些功能
set -o 表示啟用
set +o 表示禁用
-e 等同於 -o errexit遇到命令出錯就退出
-u 是否使用沒有定義的變數,相當於-o nounset
-x 單步執行
exit命令
用戶可以在腳本中使用以下命令自定義退出狀態碼
exit [n]
腳本中一旦遇到exit命令,腳本會立即終止,然後返回狀態碼
如果exit未指定退出碼,整個腳本的最終狀態碼取決於最後一條命令的狀態碼。
例:{示例說明演示未指定退出碼的情況
[root@CentOS7 2]# cat exit.sh #!/bin/bash # echo haha ech haha exit [root@CentOS7 2]# ./exit.sh haha ./exit.sh: line 4: ech: command not found [root@CentOS7 2]# echo $? 127
printf命令
printf "指定的格式" 文本1 文本2.。。 按照指定格式顯示指定文本
%s 字元串格式,%-#.##s中,#表示顯示字元寬度,數字不足的用空格補足,##表示顯示小數個數,-表示左對齊
%f 浮點型格式
%b 相對應的參數中包含轉義字元時,可以使用此替換符進行替換,對應的轉義字元會被轉義
%d | %i 十進位整數
%c ASCII字元,即顯示對應參數的第一個字元
%o 八進位顯示
%u 不帶正負號的十進位顯示
%x 小寫的十六進位顯示,即a-f
%X 大寫的十六進位顯示,即A-F
%% 表示%本身
轉義字元:
\a 警告字元,會發一聲響
\b 後退一格
\f 換頁
\n 換行
\r 回車
\t 橫向製表符
\v 縱向製表符
\\ 表示\本身
二、算數運算
算數運算符
+
-
*
/
% 取模,求餘數
** 乘方
進行算數表達式
let $M+$N 不用帶$,帶上也沒問題
let M++ 讓M自增,與++M的區別是前者是先引用後自增,後者是先自增後引用
let N-- 讓N自減,與--N的區別是前者是先引用後自減,後者是先自減後引用
$[$M+$N] 不用帶$,帶上也沒問題
$(($M+$N)) 不用帶$,帶上也沒問題
expr $M + $N 在運算符兩邊要有空格,在運算乘法的時候需要轉移即\*
declare -i VAR 可以使用declare -i把變數聲明成整數,然後就可以直接運算了
三、邏輯運算
與 1&&1=1 1&&0=0 0&&1=0 0&&0=0 任何數與0相與都為假
或 1||1=1 1||0=1 0||1=1 0||0=0 任何數與1相或都為真
非 !1=0 !0=1
異或 1^0=1 1^1=0 0^0=0 0^1=0 異或是用二進位進行運算。異或的兩個值,相同為假,不同為真
兩個運算數異或得出的值,此值在與兩個運算數其中任何一個再異或,必定得出另一個運算數
示例演示用異或互換兩個變數的值
#!/bin/bash
# i=10 j=20 echo "i=$i;j=$j" #i中的值現在已經是i與j的異或值 i=$[i^j] #下句的意思是用上一句得出的異或值i,與運算數j 再次進行異或,會得出另一個運算數 j=$[i^j] #下句的意思是用上一句得出的異或值j再次與第一句中得出的異或值i進行異或,會得出另一個 運算數 i=$[i^j] echo "i=$i;j=$j"
短路運算
短路與:CMD1&&CMD2
第一個CMD1結果為0,總的結果必定為0,因此不需要執行CMD2
第一個CMD1結果為1,第二個CMD2必須要參與運算,才能得到最終結果
短路或:CMD1||CMD2
第一個CMD1結果為1,總的結果必定為1,因此不需要執行CMD2
第一個CMD1結果為0,第二個CMD2必須要參與運算,才能得到最終結果
四、條件測試
條件測試命令
test EXPRESSION
[ EXPRESSION ] 判斷式必須有空格。等同於test
[[ EXPRESSION ]]
變數測試
[ -v VAR ] 判斷變數VAR是否已經定義,True if the shell variable VAR is set.
[ -R VAR ] 判斷變數VAR是否已經定義並且已經引用,True if the shell variable VAR is set and is a name reference.
數值測試 進行數值判斷的時候不能有非數字
-eq 相等
-ne 不相等
-lt 小於
-le 小於等於
-gt 大於
-ge 大於等於
字元串測試
-z 測試變數是否為空或者沒賦值,變數未定義 或 變數裡面是空值 都為真,但是在以用變數的時候需要加上雙引號。True if string is empty.例:n="";[ -z "$n" ];echo $?
-n 判斷變數是否為非空,在引用變數的時候必須加上雙引號 True if string is not empty.例: [ -n "$mm" ]
[STRING] 判斷式中什麼也不見,預設是指判斷變數是否為非空。True if string is not empty.
= 判斷字元串是否相等,等號兩邊都有空格,True if the strings are equal.
!= 判斷字元串是否不相等,不等號兩邊都有空格,True if the strings are not equal.
> 前一個字元串的長度大於後一個字元串,True if STRING1 sorts after STRING2 lexicographically.
< 前一個字元串的長度小於後一個字元串,True if STRING1 sorts before STRING2 lexicographically.
[ $mm ] 如果什麼也不跟,是為了判斷變數mm長度是否非零,True if string is not empty.
示例演示[ $mm ]
[root@CentOS8 7]# mm="" [root@CentOS8 7]# [ $mm ] && echo haha [root@CentOS8 7]# mm="123" [root@CentOS8 7]# [ $mm ] && echo haha haha}
[[ ]] 雙中括弧的時候裡面可以用正則表達式,雙中括弧也支持通配符,一般情況下使用單中括弧
[[ "$FILE" == *.log ]] 在雙中括弧中== 後面接通配符,判斷FILE文件是不是log結尾
[[ "$IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] 在雙中括弧中=~ 後面接正則表達式
結論:在[[ == ]]這種寫法中,==右側的* 如果想做通配符,不要加"",只想做*本身含義,需要轉移或者加上雙引號
示例演示通配符 {[root@CentOS8 7]# mm=hh.tt
[root@CentOS8 7]# [ "$mm" == "*.tt" ] && echo haha [root@CentOS8 7]# [ $mm == "*.tt" ] && echo haha [root@CentOS8 7]# [[ $mm == "*.tt" ]] && echo haha [root@CentOS8 7]# [[ "$mm" == "*.tt" ]] && echo haha [root@CentOS8 7]# [[ "$mm" == "*\.tt" ]] && echo haha [root@CentOS8 7]# [[ "$mm" == *.tt ]] && echo haha haha
=~和==詳細使用介紹{
#通配符 [root@centos8 ~]#FILE=test.log [root@centos8 ~]#[[ "$FILE" == *.log ]] [root@centos8 ~]#echo $? 0 [root@centos8 ~]#FILE=test.txt [root@centos8 ~]#[[ "$FILE" == *.log ]] [root@centos8 ~]#echo $? 1 [root@centos8 ~]#[[ "$FILE" != *.log ]] [root@centos8 ~]#echo $? 0 #正則表達式 [root@centos8 ~]#[[ "$FILE" =~ \.log$ ]] [root@centos8 ~]#echo $? 1 [root@centos8 ~]#FILE=test.log [root@centos8 ~]#[[ "$FILE" =~ \.log$ ]] [root@centos8 ~]#echo $? 0 [root@centos8 ~]#N=100 [root@centos8 ~]#[[ "$N" =~ ^[0-9]+$ ]] [root@centos8 ~]#echo $? 0 [root@centos8 ~]#N=Magedu10 [root@centos8 ~]#[[ "$N" =~ ^[0-9]+$ ]] [root@centos8 ~]#echo $? 1 [root@centos8 ~]#IP=1.2.3.4 [root@centos8 ~]#[[ "$IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] [root@centos8 ~]#echo $? 0 [root@centos8 ~]#IP=1.2.3.4567 [root@centos8 ~]#[[ "$IP" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}$ ]] [root@centos8 ~]#echo $? 1 [root@centos8 ~]#[[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3} ([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] [root@centos8 ~]#echo $? 1 #通配符 [root@centos8 ~]#NAME="linux1" [root@centos8 ~]#[[ "$NAME" == linux* ]] [root@centos8 ~]#echo $? 0 [root@centos8 ~]#[[ "$NAME" == "linux*" ]] [root@centos8 ~]#echo $? 1 [root@centos8 ~]#NAME="linux*" [root@centos8 ~]#[[ "$NAME" == "linux*" ]] [root@centos8 ~]#echo $? 0
#結論:[[ == ]] == 右側的 * 做為通配符,不要加“”,只想做為*, 需要加“” 或轉義
文件測試
-a 文件是否存在,True if file exists.
-e 文件是否存在 等同於-a, -e選項常用,True if file exists.
-b 文件是否是塊文件,True if file is block special.
-c 文件是否是字元文件,True if file is character special.
-d 判斷是不是目錄,True if file is a directory.
-f 判斷是不是普通文件,在判斷軟連接的時候,會追蹤軟連接指向的文件,True if file exists and is a regular file.
-h 或 -L 判斷是不是軟連接,True if file is a symbolic link.
-p 判斷是不是管道文件,True if file is a named pipe.
-S 大寫,判斷是不是套接字文件
文件新舊比較
-ot old than,True if file1 is older than file2.
-nt new than,True if file1 is newer than file2
-ef 判斷是不是硬鏈接,True if file1 is a hard link to file2.
文件許可權測試
-w 判斷文件是否有寫許可權,判斷最終的許可權,而不是看錶面ll的顯示結果,True if the file is writable by you.
-x 判斷文件是否有執行許可權,判斷最終的許可權,而不是看錶面ll的顯示結果,True if the file is executable by you.
-r 判斷文件是否有讀許可權,判斷最終的許可權,而不是看錶面ll的顯示結果,True if file is readable by you.
-u FILE: 是否存在且擁有suid許可權
-g FILE: 是否存在且擁有sgid許可權
-k FILE: 是否存在且擁有sticky許可權
文件屬性測試
-s 小寫,是否存在且非空,True if file exists and is not empty.
-t 判斷文件的文件描述符是否已經打開,True if FD is opened on a terminal.
-N FILE 文件自從上一次被讀取之後是否被修改過
-O FILE 當前有效用戶是否為文件屬主
-G FILE 當前有效用戶是否為文件屬組
() 小括弧中變數會在子進程中運行,同時會繼承父進程中的變數值,但是起產生的結果不會影響父進程中的值
{} 花括弧中的變數不會在子進程中運行,會在當前進程中執行,其結果會影響話括弧外面的變數,花括弧內的最後公式需要以分號;結尾,花括弧內兩邊有空格
()和{}都能將多個命令組合在一起,批量執行.
組合測試條件
[ EXPRESSION1 -a EXPRESSION2 ] 並且,表達式1和表達式2,結果才為真,True if both expr1 AND expr2 are true.
[ EXPRESSION1 -o EXPRESSION2 ] 或者,表達式1和表達式2只要一個為真,結果就為真,會進行短路運算,True if either expr1 OR expr2 is true.
[ ! EXPRESSION ] 取反,True if expr is false.
-a和-o選項只能在單中括弧內使用,不能再[[ ]]內使用。
COMMAND1 && COMMAND2 並且,短路與,代表條件性的AND THEN。如果COMMAND1 成功,將執行COMMAND2,否則,將不執行COMMAND2
COMMAND1 || COMMAND2 或者,短路或,代表條件性的OR ELSE。如果COMMAND1 成功,將不執行COMMAND2,否則,將執行COMMAND2
! COMMAND 非,取反
如果&&和||同時使用,一般情況下&&放在前面給,||放在後面。
六、條件判斷
順序執行:
;分號
if語句
單分支:
if COMMANDS; then
COMMANDS
fi
雙分支:
if EXPRIESSION;then
COMMANDS
else
COMMANDS
fi
多分支:
if EXPRIESSION;then
COMMANDS
elif EXPRIESSION; then
COMMANDS
elif EXPRIESSION; then
COMMANDS
fi
case語句
case WORD in
[PATTERN])
COMMAND
;;
[PATTERN])
COMMAND
;;
*)
COMMAND
;;
esac
PATTER