shell编程快速入门(一)
shell腳本書寫規范
shell腳本編程規范與書寫習慣
1.開頭加腳本解釋器 2.附帶作者及版權信息 3.腳本擴展名為 *.sh 4.腳本存放在固定的目錄下 5.腳本盡量不使用中文 6.成對的符號 一次性書寫完成 7.循環格式一次輸入完成 8.中括號首尾要有一個空格shell腳本的注釋
# 后面的的內容一般為注釋,可以使用vim 命令模式ctrl+v 可視化模塊添加。也可以使用如下方法: :<<EOF 需要注釋的內容 EOF注:結尾的EOF必須從行首寫,不能有空格, :冒號在shell中也是命令,表示深度不做。例如: #!/bin/bash echo "123" :<<EOF echo "234" echo "345" EOFshell腳本的執行
1.當腳本每可執行權限或腳本開頭文件沒有指定解釋器時推薦使用: bash script_name sh script_name2.指定當前路徑下執行腳本(腳本需要有執行權限) chmod +x script_name 再執行 /path/script_name ./script_name3.其他 cat script_name | sh source script_name sh < script_name . script_name父shell和子shell的概念
在A腳本運行b腳本,那么可以稱b為A的子shell,A為父shell。 父shell和子shell之間是不能調用的,若需要調用變量需要使用source或 . 點。例如: [root@m01 scripts]# cat 2.sh #!/bin/bash user=`whoami` [root@m01 scripts]# sh 2.sh [root@m01 scripts]# echo $user [root@m01 scripts]# user=`whoami` [root@m01 scripts]# echo $user root [root@m01 scripts]# unset user [root@m01 scripts]# echo $user[root@m01 scripts]# # 使用source調用是可以讀取到變量的 [root@m01 scripts]# source 2.sh [root@m01 scripts]# echo $user root總結: 使用source 和 . 點來執行腳本,相當于在shell下面執行腳本,變量互相可以調用。 bash和sh執行腳本,等于開啟了一個新的shell,或者說開啟了一個子shell,無法讀取父定義的變量。declare命令
聲明變量,設置或顯示變量的值和屬性
例: 聲明變量 [root@m01 scripts]# declare B=aaa [root@m01 scripts]# echo $B aaaunset命令
刪除指定shell變量或函數
參數: -f 僅刪除函數 -v 僅山粗變量(不包括只讀變量) -n 刪除具有引用屬性的變量名(如果該選項存在)案例: [root@m01 scripts]# a=123 [root@m01 scripts]# echo $a 123 [root@m01 scripts]# unset a #刪除指定shell變量 [root@m01 scripts]# echo $a[root@m01 scripts]#set命令
顯示或設置特殊及shell變量。
set命令注意作用是顯示系統中已經存在的shell變量,以及設置shell變量的新變量值。set命令不能定義新的shel變量,如有要定義新的變量可以使用declare命令以 “變量名=值” 的格式定義。參數: -a 標示以修改的變量,以供輸出值環境變量 -f 取消使用通配符 -n 只讀指令,而不實際執行例: [root@m01 scripts]# set |grep LANG LANG=en_US.UTF-8env命令
顯示系統中已存在的環境變量
例: 過濾系統環境變量 [root@m01 scripts]# env |grep LANG LANG=en_US.UTF-8tee命令
從標注輸入讀取數據并重定向到標準輸出和文件;要食醋胡的文件可以是一個或多個。
參數: -a 追加到文件中而不是覆蓋案例: 將信息通過管道符輸出到標準輸出并覆蓋寫入到文件中,加-a參數是追加而不是覆蓋 [root@m01 scripts]# cat 2.sh | tee 2.txt #!/bin/bash user=`whoami` [root@m01 scripts]# cat 2.txt #!/bin/bash user=`whoami`readonly命令
標記shell變量或函數為只讀
主要用途: 定義一個到多個變量并設置為只讀屬性 顯示全部包含只讀屬性的變量/函數參數: -a 指向數組 -A 指向關聯數組 -f 指向函數 -p 顯示全部只讀變量 -- 在它之后的選項無效只讀變量:是指不能被清除或重新賦值的變量。declare無法去除只讀屬性,unset不能刪除只讀變量。案例: 標記變量為只讀變量 [root@m01 scripts]# A=XXX [root@m01 scripts]# readonly A [root@m01 scripts]# A=yyy -bash: A: readonly variable [root@m01 scripts]# unset A=yyy -bash: unset: `A=yyy': not a valid identifier刪除只讀變量 cat << EOF| gdb attach $$ call unbind_variable("變量名") detach EOF變量知識
什么是變量
變量源自數學,是計算機語言中能存儲計算結果或能表示值的抽象概念。shell變量特性
默認情況下,在bash shell中是不會區分變量是什么類型的,如:常見的變量類型為整數,字符串,小數等。shell變量分類
變量可以分為兩類: 環境變量(全局變量):可以在創建他們的shell及其派生出來的任意子進程中使用,環境變量又可以分為自定義環境變量和bash內置環境變量。 普通變量(局部變量):只能在創建他們的shell函數或shell腳本中使用,普通變量一般由開發者在開發腳本程序是創建。定義環境變量
如:PS1;PATH;HOME;UID等系統固有的,默認就表示一定的意義。系統級:/etc/profile /etc/bashrc 用戶級:~/.bash_profile ~/.bashrc ~/.bash_logout ~/.bash_history設置環境變量有三種方法: 第一種: export A=1 第二種: B=2 export B 第三種: declare -x C=3總結: 定義環境變量盡量大寫; 使環境變量全局生效,可以寫入/etc/profile文件中。 顯示環境變量使用env和set命令 取消環境變量是 unset + 變量名1 變量名2 ...定義永久變量
本地變量:用戶私有變量,只有本用戶可以使用,保存在家目錄下的.bash_profile,.bashrc文件中 全局變量:所有用戶都可以使用,保存在/etc/profile,/etc/bashrc文件中例如: 本地變量 [root@www ~]# tail -1 ~/.bash_profile name='ccc'全局變量 [root@www ~]# tail -1 /etc/profile export age=18環境變量初始化與對于文件生效順序
先加載/etc/profile;然后加載~/.bash_profile;再加載~/.bashrc;最后加載/etc/bashrc普通變量(局部變量)
當前用戶或腳本種生效,離開當前用戶或腳本失效。
變量名: 規則:字母,數字,下劃線,三種組合,以字母開頭,中間不能有空格,不能使用數字開頭。 要求:見名知意 駝峰語法:首個單詞字母小寫,其余單詞首字母大寫。 例如: MyAge=18 my_age=18 myAge=18變量內容: 字符串: 變量名=value #不加引號,解析變量或者命令,然后輸出,出數字選擇不加引號,value 值。 變量名='value' #加單引號,所見即所得 變量="value" #加雙引號,解析變量或命令,然后輸出,字符串默認選擇雙引號,可以把要定義的內容作為一個整體。命令變量: 變量名=`ls` 變量名=$(ls)普通變量定義及輸出小結: 變量名: 1)變量名定義要有一定的命令規范,并且要見名知意,推薦使用駝峰語法,myAge=18 2)變量名僅能使用字母,數字,下劃線中的任意多個字符,并且盡量以字母開頭變量內容: 在腳本中定義普通字符串變量,盡量把變量的內容用雙引號括起來 單純數字的變量內容可以不加引號 希望變量的內容原樣輸出加單引號 希望變量值引用命令并且獲取命令結果使用反引號或$()賦值符號: 變量定義是賦值符號(=),賦值符號兩端不要有空格變量輸出: 使用或輸出變量的內容可以使用$變量名,例:echo $變量名 若變量名后面有其他字符連接的時候,就必須給變量加上大括號{};例如:$db_t 就要改寫成${db}_特殊重要變量
特殊位置參數變量
| $0 | 獲取當前執行shell腳本的文件名,如果執行腳本帶路徑,那么就包括腳本路徑 |
| $n | 獲取當前執行的shell腳本的第n個參數值,n=1…9,當n為0時如上;如果n>9,則大括號括起來,如${10},這樣才能代表第10個參數 |
| $# | 獲取當前執行的shell腳本后面接的參數的總個數 |
| $* | 獲取當前shell腳本所有傳參的參數,不加引號同 @ ; 如 果 給 @;如果給 @;如果給*加上雙引號,例如: "$*",則表示將所有的參數視為單個字符串,相當于"$1 $2 $3" |
| $@ | 獲取當前shell腳本所有傳參的參數,不加引號同 ? , 如 果 給 * ,如果給 ?,如果給@加上雙引號,例如:"$@",則表示將所有的參數視為不同的獨立字符串,相當于"$1" “$2” “ 3 " " . . . " , 這 是 將 多 參 數 傳 遞 給 其 他 程 序 的 最 佳 方 式 , 因 為 它 會 保 留 所 有 內 嵌 的 每 個 參 數 里 的 任 何 空 白 。 當 " 3" "...",這是將多參數傳遞給其他程序的最佳方式,因為它會保留所有內嵌的每個參數里的任何空白。當" 3""...",這是將多參數傳遞給其他程序的最佳方式,因為它會保留所有內嵌的每個參數里的任何空白。當"@“和”$*” 都加上雙引號時,二者有區別,都不加雙引號,二者無區別。 |
shell變量字串知識及實踐
| ${parameter} | 返回變量$parametert的內容 |
| ${#parameter} | 返回變量$parameter內容的長度(按字符),也適合特殊變量 |
| ${parameter:offset} | 在變量${parameter}中,從位置offset之后開始提取子串到結尾 |
| ${parameter:offset:length} | 在變量${parameter}中,從位置offset之后開始提取長度未length的子串 |
| ${parameter#word} | 從變量${parameter}開頭開始刪除最短匹配的word子串 |
| ${parameter##word} | 從變量${parameter}開頭開始刪除最長匹配的word子串 |
| ${parameter%word} | 從變量${parameter}結尾開始刪除最短匹配的word子串 |
| ${parameter%%word} | 從變量${parameter}結尾開始刪除最長匹配的word子串 |
| ${parameter/pattern/string} | 使用string代替第一個匹配的pattern |
| ${parameter//pattern/string} | 使用string代替所有匹配的pattern |
變量內容"子串"的刪除和替換(重點)
====內容的刪除==== [root@m01 ~]# url=www.sina.com.cn 1.${parameter}案例:獲取變量內容 [root@m01 ~]# echo ${url} www.sina.com.cn2.${#parameter}案例:獲取變量值的長度 [root@m01 ~]# echo ${#url} 15====索引切片==== 3.${parameter:offset}案例:在變量${parameter}中,從位置offset之后開始提取子串到結尾 [root@m01 ~]# echo ${url:2} w.sina.com.cn [root@m01 ~]# echo ${url:3} .sina.com.cn4.${parameter:offset:length}案例:從變量${parameter}中從位置offset之后開始提取長度未length的子串 [root@m01 ~]# echo ${url:3:4} .sin [root@m01 ~]# echo ${url:1:3} ww.5.${parameter#word}案例:從變量${parameter}開頭刪除最短匹配的word子串 [root@m01 ~]# echo ${url#*.} sina.com.cn [root@m01 ~]# echo ${url#*c} om.cn6.${parameter##word}案例:${parameter}開頭刪除最長匹配的word子串 [root@m01 ~]# echo ${url##*.} cn [root@m01 ~]# echo ${url##*c} n#發現沒有刪除內容,是因為從前往后,a.之前還有內容,寫法錯誤,所以無法刪除 [root@m1 ~]$ echo ${url#a.} www.sina.com.cn [root@m1 ~]$ echo ${url#*a.} 這樣寫就可以了 com.cn7.${parameter%word}案例:從變量${parameter}`結尾`開始刪除`最短`匹配的word子串 [root@m01 ~]# echo ${url%cn} www.sina.com. [root@m01 ~]# echo ${url%.*} www.sina.com [root@m01 ~]# echo ${url%m.cn} www.sina.co8.${parameter%%word}案例:從變量${parameter}`結尾`開始刪除`最長`匹配的word子串 [root@m01 ~]# echo ${url%%.*} www對比 [root@m01 ~]# a=tianyun.1000phone.com [root@m01 ~]# echo ${a%.*} #匹配最短 tianyun.1000phone [root@m01 ~]# echo ${a%%.*} #匹配最長 tianyun===變量替換=== 9.${parameter/pattern/string}案例:使用string代替第一個匹配的pattern [root@m01 ~]# echo ${url/n/N} www.siNa.com.cn [root@m01 ~]# echo ${url/w/W} Www.sina.com.cn10.${parameter//pattern/string}案例:使用string代替所有匹配的pattern [root@m01 ~]# echo ${url//n/N} www.siNa.com.cN [root@m01 ~]# echo ${url//w/W} WWW.sina.com.cnshell特殊變量擴展知識
${parameter:-word} 如果parameter變量值為空或未賦值,就返回word字符串替代變量的值。冒號是可以省略的。 用途:如果變量為定義,則返回備用值,防止變量為空值或未定義而導致異常。 例: [root@m01 ~]# result=${test:-test1} [root@m01 ~]# echo $test [root@m01 ~]# echo $result test1 [root@m01 ~]# echo $test [root@m01 ~]# #以上說明短橫線的作用:當變量值為空時,短橫線后面的值會賦值給變量,當不為空時,不能覆蓋原來的值 ${變量名-新的變量名} 變量沒有被賦值:會使用“新的變量值”替代 變量有被賦值(包括空值):不會被替代企業應用:防止變量為空從根刪起--造成誤刪 find ${path:-/tmp} -name "*.log" -mtime +7|xargs rm -f [root@m01 ~]# find ${path:-/tmp} -name "*.log" /tmp/glances.log [root@m01 ~]# path=/opt [root@m01 ~]# find ${path:-/tmp} -name "*.log" [root@m01 ~]# touch /opt/c.log [root@m01 ~]# find ${path:-/tmp} -name "*.log" /opt/c.log${parameter:=word} 如果parameter變量值為空或未賦值,就設置這個變量值為word,并返回其值。位置變量和特殊變量不適用。 用途:基本同上一個${parameter:-word} ,但是又額外給parameter變量賦值了。 例: [root@m01 ~]# echo $test[root@m01 ~]# result=${test:=test1} [root@m01 ~]# echo $result test1 [root@m01 ~]# echo $test test1 #當test值為空,test1的值不但會賦值給test還會賦值給result.${parameter:?word} 如果parameter變量值為空或未賦值,word字符串將被作為標準錯誤輸出,否則輸出變量的值。用途:用于捕捉由于變量未定義而導致的錯誤,并退出程序。 例如: [root@m01 ~]# result=${test2:?變量內容為空} -bash: test2: 變量內容為空 [root@m01 ~]# test2=xxx [root@m01 ~]# echo $test2 xxx [root@m01 ~]# result=${test2:?變量內容為空} [root@m01 ~]# result=${test2:?變量內容為空} #如果parameter值為空,就報錯,否則就輸出變量的值${parameter:+word}如果parameter變量值為空或未賦值,則什么都不做,否則word字符串替代變量的值。 例如: [root@m01 ~]# result1=${test3:+heihei} [root@m01 ~]# echo $result1[root@m01 ~]# echo $test3[root@m01 ~]# test3=333 [root@m01 ~]# result1=${test3:+heihei} [root@m01 ~]# echo $result1 heihei [root@m01 ~]# echo $test3 333 #意思就是test3值為空時,什么都不做,否則將值賦值給result1shell進程特殊狀態變量
| $? | 獲取執行上一個指令的執行狀態,返回值為0是成功,非0為失敗 |
| $$ | 或者當前執行的shell腳本的進程號(PID)。(后面三個,了解即可) |
| $! | 獲取上一個在后臺工作的進程的進程號(PID) |
| $__ | 獲取在此之前執行的命令或腳本的最后一個參數 |
shell變量的數值計算實踐
expr命令
expr是一款便打算計算工具,使用它完成表達式的求值操作
expr的常用運算:加減乘除,求模也就是取余運算%。 更多用法參考:man expr1.在shell編程中,常用來判斷一個數是否為整數。 [root@m01 scripts]# cat test2.sh #!/bin/bash expr 2 + $1 &>/dev/null if [ $? -eq 0 ] thenecho "$1 is integer" elseecho "$1 is noninteger" fi [root@m01 scripts]# sh test2.sh 1 1 is integer [root@m01 scripts]# sh test2.sh 1.1 1.1 is noninteger2.通過expr判斷文件擴展名 [root@m01 scripts]# cat expr1.sh #!/bin/bash expr "$1" : ".*\.txt" &>/dev/null if [ $? -eq 0 ] thenecho "$1 是文本" elseecho "$1 不是文本" fi [root@m01 scripts]# sh expr1.sh hh.txt hh.txt 是文本 [root@m01 scripts]# sh expr1.sh hh.html hh.html 不是文本3.通過expr計算字符串的長度 [root@m01 scripts]# char="I love linux and python" [root@m01 scripts]# expr length "$char" 23其他計算字符串長度的方法: [root@m01 scripts]# echo ${#char} 23 [root@m01 scripts]# echo ${char} |wc -L 23 # -L 打印最長行的長度[root@m01 scripts]# echo ${char} |awk '{print length(($0))}' 23[root@m01 scripts]# echo ${char} |awk '{print length}' 23算數運算
| + - | 加法或正號;減法或負號 |
| * / % | 乘法;除法;取余(取模) |
| ** | 冪運算 |
| ++ – | 增加及減少,可以前置也可以放在變量結尾,默認步長為1 |
| ! && || | 邏輯非(取反);邏輯與(and);邏輯或(or) |
| < <= > >= | 比較符號,小于,小于等于,大于,大于等于 |
| == != = | 比較符號,相等,不相等,對于字符串"="也可以表示相等 |
| << >> | 向左位移,向右位移 |
| ~ | & ^ | 按位取反;按位異或;按位與;按位或 |
| = += -= *= /= %= | 賦值運算,例如a+=1等同a=a+1,a-=1等同a=a-1 |
bash編程常見運算命令匯總
| (()) | 用于整數運算的常用運算符,效率很高 |
| let | 用于整數運算,類似(()) |
| expr | 可以用于整數運算,還有其他的額外功能,如判斷是否為整數 |
| bc | Linux下的一個計算器程序(適合整數以及小數運算) |
| $[] | 用于整數運算 |
| awk | 即可用于整數運算,也可以用于小數運算 |
| declare | 定義變量值和屬性,-參數可以用于定義整形變量,做運算 |
特殊內置命令read
從鍵盤讀取變量值,通常在shell腳本中與用戶交互的場合使用。該命令可以一次性讀取多個變量的值,變量和輸入的值都需要使用空格隔開。在read命令后面,如果沒有指定變量名,讀取的數據將被自動賦值給特定的變量REPLY。
參數: -p 指定讀取值時的提示符 -t 指定讀取值時等待的時間,默認單位秒 -s 不回顯 -n 輸入字符個數案例: [root@m01 scripts]# read -t 5 -p "請輸入一個數值:" a 請輸入一個數值:20 [root@m01 scripts]# echo $a 20shell案例 通過read方式讀入整數變量,計算兩個數的加減乘除冪模運算 [root@m01 scripts]# cat read.sh #!/bin/bash read -p "請輸入兩個整數:" a b echo "a+b=$(($a+$b))" echo "a+b=$(($a-$b))" echo "a+b=$(($a*$b))" echo "a+b=$(($a/$b))" echo "a+b=$(($a**$b))" echo "a+b=$(($a%$b))" [root@m01 scripts]# sh read.sh 請輸入兩個整數:2 2 a+b=4 a+b=0 a+b=4 a+b=1 a+b=4 a+b=0也可以通過傳參的方式 [root@m01 scripts]# cat read1.sh #!/bin/bash a=$1 b=$2 echo "a+b=$(($a+$b))" echo "a+b=$(($a-$b))" echo "a+b=$(($a*$b))" echo "a+b=$(($a/$b))" echo "a+b=$(($a**$b))" echo "a+b=$(($a%$b))" [root@m01 scripts]# sh read1.sh 2 2 a+b=4 a+b=0 a+b=4 a+b=1 a+b=4 a+b=0擴展1 [root@m01 scripts]# cat read.sh #!/bin/bash read -p "請輸入兩個整數:" a b c if [ -z $a ] thenecho "error1:必須是兩個整數"exit elif [ -z $b ] thenecho "error2:必須是兩個整數"exit fiif [ -z $c ] thenexpr $a + $b + 3 &>/dev/nullif [ $? -eq 0 ]thenecho "a+b=$(($a+$b))"echo "a+b=$(($a-$b))"echo "a+b=$(($a*$b))"echo "a+b=$(($a/$b))"echo "a+b=$(($a**$b))"echo "a+b=$(($a%$b))"elseecho "輸入的不是整數"exitfi elseecho "error3:必須是兩個整數" fi [root@m01 scripts]# sh read.sh 請輸入兩個整數:1 2 a+b=3 a+b=-1 a+b=2 a+b=0 a+b=1 a+b=1 [root@m01 scripts]# sh read.sh 請輸入兩個整數:w 1 輸入的不是整數 [root@m01 scripts]# sh read.sh 請輸入兩個整數:2 e 輸入的不是整數 [root@m01 scripts]# sh read.sh 請輸入兩個整數:33 3 3 error3:必須是兩個整數 [root@m01 scripts]# sh read.sh 請輸入兩個整數:1 2 3 4 read.sh: line 13: [: 3: binary operator expected error3:必須是兩個整數 [root@m01 scripts]# sh read.sh 請輸入兩個整數:1 1.1 輸入的不是整數# 當腳本較為繁雜時,就不適合使用read,但是read和用戶交互性較好。擴展2,使用傳參的方式 [root@m01 scripts]# cat test.sh #!/bin/bash a=$1 b=$2 if [ $# -ne 2 ] thenecho "只能輸出兩個整數"exit 1 elseexpr $a + $b + 3 &>/dev/nullif [ $? -eq 0 ]thenecho "a+b=$(($a+$b))"echo "a+b=$(($a-$b))"echo "a+b=$(($a*$b))"echo "a+b=$(($a/$b))"echo "a+b=$(($a**$b))"echo "a+b=$(($a%$b))"elseecho "輸入的不是整數"exit 2fi fi [root@m01 scripts]# sh test.sh 1 2 a+b=3 a+b=-1 a+b=2 a+b=0 a+b=1 a+b=1 [root@m01 scripts]# sh test.sh 1 2 3 只能輸出兩個整數 [root@m01 scripts]# sh test.sh w 2 3 只能輸出兩個整數 [root@m01 scripts]# sh test.sh 1 w 3 只能輸出兩個整數 [root@m01 scripts]# sh test.sh 1 2 e 只能輸出兩個整數 [root@m01 scripts]# sh test.sh 1.1 2 輸入的不是整數關于cat<<EOF的使用方法
cat<<EOF是從標準輸入設備(一般為鍵盤)獲取輸入,在第二個EOF處結束輸入,同時輸出到輸出設備(一般為顯示器)。 例如: [root@m01 scripts]# [root@m01 scripts]# cat <<EOF > This is test file! > EOF This is test file! #結束的EOF必須是行首,否則被視為標準輸入而不是結束分解符。shell腳本的條件測試與比較
通常,在bash的各種條件結構和流程控制中都要進行各種測試,然后根據測試結果執行不同的操作,有時也會與if等條件語句相結合,來完成測試判斷,減少程序運行的錯誤,執行測試條件表達式后通常會返回真或假,就像執行命令后的返回值為0和非0表示真假一樣。
test命令
執行條件表達式
參數: 文件操作符 常用: -a FILE 如果文件存在,則為true -d FILE 如果文件是目錄,則為true -e FILE 如果文件存在,則為true -f FILE 如果文件存在且為普通文件,則為true -L FILE 如果文件是鏈接文件,則為true -r FILE 如果文件可以讀取,則為true -s FILE 如果文件存在且不為空(大小不為0),則為true -w FILE 如果文件可寫,則為true -x FILE 如果文件可以執行,則為true常用字符串運算符: -z STRING 如果字符串為空,則為true -n STRING 如果字符串不為空,則為true STRING 如果字符串不為空,則為true STRING1 = STRINFG2 如果字符串相等,則為true STRING != STRING2 如果字符串不相等,則為true文件比較: FILE1 -nt FILE2 根據修改日期,如果file1 比 file2 新,則為true FILE1 -ot FILE2 根據修改日期,如果file1 比 file2 舊,則為true FILE1 -ef FILE2 如果file1 為 file2的硬連接,則為true返回值:如果表達式執行結果為成功時返回0,當表達式執行結果為失敗或給出非法參數時返回1。其他了解即可: 可參考:https://wangchujiang.com/linux-command/c/test.html 或者其他參考man 手冊案例: [root@m01 scripts]# test -a /etc/passwd [root@m01 scripts]# echo $? 0 [root@m01 scripts]# test -a /etc/passddd [root@m01 scripts]# echo $? 1六種條件測試語法
| test <測試表達式> | test命令和 "<測試表達式>"之間至少有一個空格 |
| [ <測試表達式> ] | 單中括號邊界和內容至少有一個空格 |
| [[ <測試表達式> ]] | 雙中括號邊界和內容之間至少有一個空格,比[]更新的語法格式;推薦使用 |
| ((<測試表達式>)) | 雙小括號一般用于if語句中,雙小括號兩端不需要有空格 |
| (<測試表達式>) | 小括號應用較少,了解即可 |
| `<測試表達式>``` | 通過反引號實現測試條件表達式,應用較少,了解即可 |
條件表達式的編程語法
[ <測試表達式> ] && 命令 如果前面的表達式成立,那么就執行后面的命令[ <測試表達式> ] || 命令 如果前面的表達式不成立,那么就執行后面的命令[ <測試表達式> ] && { 命令1 命令2 命令3 } 如果前面的表達式成立,那么就執行后面的命令[ <測試表達式> ] && 命令1 ||命令2 如果前面的表達式成立,那么就執行命令1,否則就執行命令2[ <測試表達式> ] && { 命令1 命令2 } || { 命令3 命令4 } 如果表達式成立,那么就執行命令1,2否則執行命令3,4整數測試表達式
| -eq | ==或= | 相等全拼equal |
| -ne | != | 不相等全拼not equal |
| -gt | > | 大于 greater than |
| -ge | >= | 大于等于,greater equal |
| -lt | < | 小于,less than |
| -le | <= | 小于等于,less equal |
邏輯測試表達式
| -a | && | and,與,兩端都為真則真 |
| -o | || | or,或,兩端有一個為真則真 |
| ! | ! | not 非,相反則為真 |
條件表達式符號的語法對比
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ielgGMYT-1614393493074)(https://i.loli.net/2021/02/20/hyTE6tzMZdkFWln.png)]
vim編程環境配置
[root@m01 ~]# pwd /root[root@m01 ~]# cat .vimrc set nocompatible set history=100 filetype on filetype plugin on filetype indent on set autoread set mouse=c syntax enable set cursorline hi cursorline guibg=#00ff00 hi CursorColumn guibg=#00ff00 set foldenable set foldmethod=manual set foldcolumn=0 setlocal foldlevel=3 set foldclose=all nnoremap <space> @=((foldclosed(line('.')) < 0) ? 'zc' : 'zo')<CR> set expandtab set tabstop=4 set shiftwidth=4 set softtabstop=4 set smarttab set ai set si set wrap set sw=4 set wildmenu set ruler set cmdheight=1 set lz set backspace=eol,start,indent set whichwrap+=<,>,h,l set magic set noerrorbells set novisualbell set showmatch set mat=4 set hlsearch set ignorecase set encoding=utf-8 set fileencodings=utf-8 set termencoding=utf-8 set smartindent set cin set showmatch set guioptions-=T set guioptions-=m set vb t_vb= set laststatus=4 set pastetoggle=<F9> set background=dark set t_ti= t_te= highlight Search ctermbg=black ctermfg=white guifg=white guibg=black autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1, "#!/bin/bash")call setline(2, "##############################################################") call setline(3, "# File Name: ".expand("%"))call setline(4, "# Version: V1.0")call setline(5, "# Author: daveorff")call setline(6, "# Organization:")call setline(7, "# Created Time : ".strftime("%F %T"))call setline(8, "# Description:")call setline(9, "##############################################################")endif endfuncshell腳本調試之sh命令
shell命令解釋器
參數: -c string 命令從-c后的字符串讀取 -i 實現腳本交互 -n 進行shell腳本的語法檢查 -x 實現shell腳本的逐條語句的跟蹤應用 sh -n filename.sh 僅調試 sh -vx filename.sh 以調試的方式執行,查詢整個執行過程 使用-x參數跟蹤腳本調試shell腳本,能打印除所執行的每一行命令以及當前狀態if結構條件語句知識與實踐
簡單理解:如果…那么…否則…
單分支
if <條件表達式> then指令 fi雙分支
if <條件表達式> then指令 else指令2 fi多分支
if條件多分枝結構主體為 "如果...,那么...,否則如果,那么,否則如果...那么...,...,否則..."if <條件表達式1> then指令1 elif <條件表達式2> then指令2 elif <條件表達式3> then指令3 else指令4 fi嵌套if
if <條件表達式1> then指令1 else指令2if <條件表達式2>then指令3fi fi 邏輯不清晰,不推薦使用,可以使用多個if分支。實踐
例1:如果不存在/backop目錄就創建,存在則打印exist [root@m01 scripts]# vim 01_01.sh #!/bin/bash path="/backup" if [[ -d $path ]] thenecho "eixst" elsemkdir $path -p fi執行 [root@m01 scripts]# sh 01_01.sh [root@m01 scripts]# sh 01_01.sh eixst案例2:開發shell腳本判斷系統剩余內存的大小,如果低于100MB就提示內存不足,否則提示內存充足 分析:先取內存 [root@m01 ~]# free -mtotal used free shared buff/cache available Mem: 3773 124 3488 11 160 3429 Swap: 1999 0 1999 字段結束: total 內存總數 used 已經使用的內數 free 空閑的內存數 shared 是指共享的 buffes 是指緩沖內存數 cached 是指緩存內存數,單位是kb 關系:total=used+free使用awk取值 [root@m01 ~]# free -m | awk 'NR==2{print $4}' 3475再寫if語句 [root@m01 scripts]# vim 02.sh #!/bin/bash mem=`free -m | awk 'NR==2{print $4}'` if [[ $mem -le 100 ]] thenecho "內存不足" elseecho "內存充足" fi#測試 [root@m01 scripts]# sh 02.sh 內存充足 [root@m01 scripts]# sh 02.sh 內存充足#改到4000測試 [root@m01 scripts]# sh 02.sh 內存不足案例3: 分別使用變量定義,read讀入及腳本傳參方式實現比較兩個整數的大小 1.read讀入方式: 解析:可以在傳入的時候設置3個參數,以達到判斷是否多出兩個整數的目的 先使用rend讀入兩個整數 read -p "請讀入兩個整數:" a b c 判斷輸入整數個數是否小于2 方法:判斷b是否為空 只有不為空繼續下一步,否則退出 判斷輸入整數個數是否大于2,判斷c是否為空,只有為空才進行下一步,否則退出 如果是再判斷是否是兩個整數 :如果兩個數都是整數則進行下一步,否則退出 expr $a + $b + 3 &>/dev/null 如果都滿足則比較大小 [root@m01 scripts]# cat 03_01.sh #!/bin/bash read -p "請輸入兩個整數:" a b c if [[ -z $b ]] thenecho "缺失一個數,請輸入兩個整數"exit 1 fiif [[ -n $c ]] thenecho "參數個數大于2,請輸入兩個整數"exit 2 fiexpr $a + $b + 1 &>/dev/null if [[ $? -ne 0 ]] thenecho "只能比較整數"exit 3 fiif [[ $a -lt $b ]] thenecho "$a < $b" elif [[ $a -gt $b ]] thenecho "$a > $b" elseecho "$a = $b" fi使用傳參的方式: [root@m01 scripts]# cat 03_02.sh #!/bin/bash a=$1 b=$2 if [[ $# -ne 2 ]] thenecho "參數個數不對,請輸入兩個整數"exit 1 fiexpr $a + $b + 3 &>/dev/null if [[ $? -ne 0 ]] thenecho "只能比較整數"exit 2 fiif [[ $a -lt $b ]] thenecho "$a < $b" elif [[ $a -gt $b ]] thenecho "$a > $b" elseecho "$a = $b" fi案例4: 打印一個菜單如下,當用戶選擇對應的數字時,就執行對應項目的應用 1.install lamp 2.install lnmp 3.exit[root@m01 scripts]# cat 04.sh #!/bin/bash cat<<EOF 1.install lamp 2.install lnmp 3.exit EOF read -p "請選擇序號1|2|3:" num expr $num + 2 &>/dev/null if [[ $? -ne 0 ]] thenecho "error1:請輸入整數"exit fiif [[ $num -eq 1 ]] thenecho "install lamp..." elif [[ $num -eq 2 ]] thenecho "instahll lnmp..." elif [[ $num -eq 3 ]] thenecho "exit"exit elseecho "請選擇序號1~3" fi嵌套if寫法: [root@m01 scripts]# cat 04_01.sh #!/bin/bash cat<<EOF 1.install lamp 2.install lnmp 3.exit EOF read -p "請選擇序號1|2|3:" num expr $num + 2 &>/dev/null if [[ $? -ne 0 ]] thenecho "error1:請輸入整數"exit elseif [[ $num -eq 1 ]]thenecho "install lamp..."elif [[ $num -eq 2 ]]thenecho "instahll lnmp..."elif [[ $num -eq 3 ]]thenecho "exit"exitelseecho "請選擇序號1~3"fi fishell函數的概念與作用及語法介紹
函數的概念與作用
簡單來說,函數的作用就是將程序多次被調用的相同代碼組合成函數體,并且為其取名,即函數名。當其他所有重復調用這部分代碼的地方只需要用這個名字即可,當需要修改這部分重復代碼時,也只需要改變函數體內的一部分代碼即可實現所有調用的修改,也可以把函數單獨的寫入文件中,當需要調用函數時,再加載來使用。
使用shell函數的優勢
- 把相同的程序段定義成函數,可以減少整個程序的代碼里,提升開發效率
- 增加函數的可讀性,易讀性,提升管理效率
- 可以實現程序功能模塊化,使得程序具備通用性,也就是可移植性
- 對應shell來說,Linux系統里近2000個命令都可以說是shell函數
**函數的多種語法 **
第一種語法: function 函數名() {指令集...return n }第二種語法: function 函數名 {指令集return n }第三種語法:(推薦) 函數名() {指令集...return n }注意空格,return 函數返回值函數的執行
不帶參數的函數執行時,直接輸入函數名即可(注意不帶小括號)。(–簡單函數執行)
案例: [root@m01 scripts]# vim func1.sh #!/bin/bash function test_1() {echo "i am function_t1" }function test_2 {echo "hello t2" }test_3() {echo "hei t3" } test_1 test_2 test_3 總結:;定義完函數后,直接使用其名字即可調用。有關函數執行的重要說明
--執行shell函數時,函數名前的function和函數的小括號都不要帶 --函數的定必須在執行前面定義或加載 --shell執行系統中各種程序的順序為:系統別名-> 函數->系統命令->可執行文件 --函數執行時,會和調用它的腳本共用變量(相當于腳本的參數與函數共用),也可以為函數設定局部變量以及特殊位置參數 --在shell函數中,return命令功能與exit類似,作用是從函數中退出并返回函數值,而exit是退出腳本文件 --return語句會返回有關退出值(即返回值)給調用函數的當前程序,而exit會返回有關退出值(即返回值)給執行程序當前shell --如果函數存放在單獨的文件中,被腳本加載使用時,需要source或 . 點來加載 --在函數內一般使用local定義局部變量,這些變量離開函數即消失,不用local可以在腳本外調用。**帶參數的函數的執行方法格式如下: ** (–函數傳參)
[root@m01 scripts]# cat func2.sh #!/bin/bash function test_1() {echo "i am $1" }function test_2 {echo "$2" }test_3() {echo "$3" } test_1 我是函數傳參1 test_2 4 5 6 test_3 7 8 9 [root@m01 scripts]# sh func2.sh i am 我是函數傳參1 5 9帶參數的函數執行格式:
函數 參數1 參數2 ...函數后接的參數說明
shell位置參數($1,$2,$3,...$#,$*,$?以及$@等)都可以作為函數的參數使用 此時父腳本的參數臨時的被函數所掩蓋或隱蔽 $0比較頁數,它仍然是父腳本的名稱 當函數執行完成時,原來的命令腳本參數即恢復 函數參數變量是函數體里面定義的#理解: #比如$?的使用;可以查看函數的執行狀態,狀態碼范圍是0-255,且$?取值是腳本的最后一條命令的狀態碼 [root@m01 scripts]# cat func3.sh #!/bin/bash function gg {echo "hello gg"return 110 } gg [root@m01 scripts]# sh func3.sh hello gg [root@m01 scripts]# echo $? 110#local的使用; [root@m01 scripts]# cat func4.sh #!/bin/bash function test_1 {local i="xiaoming"echo "i am $i" } test_1 echo $i [root@m01 scripts]# sh func4.sh i am xiaoming#從此輸出為空,在函數內一般使用local定義局部變量,這些變量離開函數后即消失 [root@m01 scripts]# #總結: #使用local后在函數之外是無法調用函數體內的變量,把local去掉就是腳本變量是可以生效的。 #建議多個函數間定義同一個變量時使用local,這樣多個函數間的同名變量便不會發生沖突。將函數傳參轉為腳本傳參 (–腳本傳參)
[root@m01 scripts]# cat func6.sh #!/bin/bash daveff() {echo "i am $1" } daveff $1 [root@m01 scripts]# sh func6.sh superman i am superman將函數體和函數執行分成不同的文件
1.將函數寫入系統函數,/etc/init.d/functions 寫入此文件最后兩行上面 例: ...fi fifunction daveorff() {echo " I am $1" }2.使用點 . 或source調用,地址為 /etc/init.d/functions [root@m01 scripts]# cat func5.sh #!/bin/bash source /etc/init.d/functions daveorff $13.測試,腳本鏈接什么參數,就輸出什么內容 [root@m01 scripts]# sh func5.sh abcI am abc [root@m01 scripts]# sh func5.sh cbaI am cba查看shell /etc/init.d/functios文件中所有的函數名grep -E "[a-zA-Z]+\(\)" /etc/init.d/functions -o總結:
函數總共有四種執行方式
函數案例
案例: 1.通過腳本傳參的方式,檢查web網站URL是否正常 解析: wget命令 --spider 不下載任何大小;模擬爬蟲 -q 安靜訪問 --quiet 安靜模式(沒有輸出) -o 把記錄寫的file文件中,加/dev/null表示不輸出 -T 超時時間,設定響應超時的秒數 -t 重試,設定最大嘗試連接次數(0表示無限制) [root@m01 ~]# wget --spider -T 5 -q -o /dev/null -t 2 www.baidu.com [root@m01 ~]# echo $? 0curl 命令 -l 值顯示請求頭信息 -s 靜默模式,不輸出任何東西 -S 顯示錯誤 -o 把輸出寫到文件,加/dev/null表示不輸出 -w % {http_code} 返回狀態碼,200為正常 -m 設置最大傳輸時間[root@m01 ~]# curl www.baidu.com -s &>/dev/null [root@m01 ~]# echo $? 0 [root@m01 ~]# curl -l -m 5 -s -w "%{http_code}\n" -o /dev/bull www.baidu.com 200不用函數的的寫法 [root@m01 scripts]# cat checkurl.sh #!/bin/bash wget --spider -T 5 -q -o /dev/null -t 2 $1 if [[ $? -eq 0 ]] thenecho "$1 is ok" elseecho "$1 is fail" fi [root@m01 scripts]# sh checkurl.sh www.baidu.com www.baidu.com is ok [root@m01 scripts]# sh checkurl.sh www.baidu.co www.baidu.co is fail使用函數寫法 [root@m01 scripts]# cat checkurl_01.sh #!/bin/bash usage(){echo "Usage: $0 url"exit 1 }checkurl(){wget --spider -T 5 -q -o /dev/null -t 2 $1if [[ $? -eq 0 ]]thenecho "is ok"elseecho "is fail"fi }main(){if [[ $# -ne 1 ]]thenusageficheckurl $1 } main $* [root@m01 scripts]# sh checkurl_01.sh www.baidu.co is fail [root@m01 scripts]# sh checkurl_01.sh www.baidu.com is okcase結構條件語句
case結構條件語句相等于多分支的if/elif/else條件語句,但是它比這條件語句看起來更加規范工整,常被用于實現系統服務啟動腳本等。
case 語法: case "變量" in值1)指令1...;;值2)指令2...;;值3)指令3...;;*)指令4... esaccase條件語句的執行流程邏輯圖
case條件語句的使用總結
1.case語句和if條件語句的適用性 case語句比較適合變量較少且為固定的數字或字符串集合的情況,而非不確定的的內容,如范圍。如果便的值是已知固定的start/stop/restart等元素,那么采用case語句實現比較合適。2.case語句和if條件語句的常見應用場景 - case主要寫服務的啟動腳本,一般情況下,傳參不同且具有少量的字符串,使用范圍較窄 - if就是取值判斷,比較,應用比case更廣,幾乎所有的case語句都可以使用if條件語句實現3.case語句的特定及優勢 case語句就相當于多分支if/elif/else語句,單case語句的優勢更規范,易讀。案例:
執行shell腳本,打印一個如下的水果菜單 1.apple 2.pear 3.banana 4.cherry 當用戶輸入對應的數字選擇水果是,告訴他選擇的水果是什么,并給水果單詞加上一種顏色,使用case語句實現。[root@m01 scripts]# cat 06.sh #!/bin/bash cat << EOF 1.apple 2.pear 3.banana 4.cherry EOFread -p "請選擇序號:" num case "$num" in1)echo -e "\033[31m apple \033[0m";;2)echo -e "\033[32m pear \033[0m" ;;3)echo -e "\033[33m banana \033[0m";;4)echo -e "\033[34m cherry \033[0m";;*)echo -e "\033[36m 請選擇1~4 \033[0m"exit esac顏色代碼
腳本中echo顯示內容帶顏色顯示,echo顯示帶顏色,需要使用參數-e格式如下: echo -e “\033[字背景顏色;文字顏色m字符串\033[0m”例如: echo -e “\033[41;36m good \033[0m” 其中41的位置代表底色, 36的位置是代表字的顏色 1、字背景顏色和文字顏色之間是英文的冒號 ";" 2、文字顏色后面有個m 3、字符串前后可以沒有空格,如果有的話,輸出也是同樣有空格內容的顏色用數字表示,范圍為30-37,每個數字代表一種顏色。代碼如下: echo -e "\033[30m 黑色字 \033[0m" #<==30m表示黑色字。 echo -e "\033[31m 紅色字 \033[0m" #<==31m表示紅色字。 echo -e "\033[32m 綠色字 \033[0m" #<==32m表示綠色字。 echo -e "\033[33m 棕色字 \033[0m" #<==33m表示棕色字(brown),和黃色字相近。 echo -e "\033[34m 藍色字 \033[0m" #<==34m表示藍色字。 echo -e "\033[35m 洋紅字 \033[0m" #<==35m表示洋紅色字(magenta),和紫色字相近。 echo -e "\033[36m 藍綠色 \033[0m" #<==36m表示藍綠色字(cyan),和淺藍色字相近。 echo -e "\033[37m 白色字 \033[0m" #<==37m表示白色字。給輸出的字符串加不同的背景顏色: 字的背景顏色對應的數字范圍為40-47,代碼如下。 echo -e "\033[40;37m 黑底白字\033[0m" #<==40m表示黑色背景。 echo -e "\033[41;37m 紅底白\033[0m" #<==41m表示紅色背景。 echo -e "\033[42;37m 綠底白字\033[0m" #<==42m表示綠色背景。 echo -e "\033[43;37m 棕底白字\033[0m" #<==43m表示棕色背景(brown),和黃色背景相近。 echo -e "\033[44;37m 藍底白字\033[0m" #<==44m表示藍色背景。 echo -e "\033[45;37m 洋紅底白字\033[0m" #<==45m表示洋紅色背景(magenta),和紫色背景相近。 echo -e "\033[46;37m 藍綠底白字\033[0m" #<==46m表示藍綠色背景(cyan),和淺藍色背景相近。 echo -e "\033[47;30m 白底黑字\033[0m" #<==47m表示白色背景。最后面控制選項說明 \033[0m 關閉所有屬性 \033[1m 設置高亮度 \033[4m 下劃線 \033[5m 閃爍 \033[7m 反顯 \033[8m 消隱 \033[30m — \33[37m 設置前景色 \033[40m — \33[47m 設置背景色 \033[nA 光標上移n行 \033[nB 光標下移n行 \033[nC 光標右移n行 \033[nD 光標左移n行 \033[y;xH設置光標位置 \033[2J 清屏 \033[K 清除從光標到行尾的內容 \33[s 保存光標位置 \033[u 恢復光標位置 \033[?25l 隱藏光標 \033[?25h 顯示光標 ;; 3)echo -e "\033[33m banana \033[0m";; 4)echo -e "\033[34m cherry \033[0m";; *)echo -e "\033[36m 請選擇1~4 \033[0m"exitesac
### 顏色代碼腳本中echo顯示內容帶顏色顯示,echo顯示帶顏色,需要使用參數-e
格式如下:
echo -e “\033[字背景顏色;文字顏色m字符串\033[0m”
例如:
echo -e “\033[41;36m good \033[0m”
其中41的位置代表底色, 36的位置是代表字的顏色
1、字背景顏色和文字顏色之間是英文的冒號 “;”
2、文字顏色后面有個m
3、字符串前后可以沒有空格,如果有的話,輸出也是同樣有空格
內容的顏色用數字表示,范圍為30-37,每個數字代表一種顏色。代碼如下:
echo -e “\033[30m 黑色字 \033[0m” #<==30m表示黑色字。
echo -e “\033[31m 紅色字 \033[0m” #<==31m表示紅色字。
echo -e “\033[32m 綠色字 \033[0m” #<==32m表示綠色字。
echo -e “\033[33m 棕色字 \033[0m” #<==33m表示棕色字(brown),和黃色字相近。
echo -e “\033[34m 藍色字 \033[0m” #<==34m表示藍色字。
echo -e “\033[35m 洋紅字 \033[0m” #<==35m表示洋紅色字(magenta),和紫色字相近。
echo -e “\033[36m 藍綠色 \033[0m” #<==36m表示藍綠色字(cyan),和淺藍色字相近。
echo -e “\033[37m 白色字 \033[0m” #<==37m表示白色字。
給輸出的字符串加不同的背景顏色:
字的背景顏色對應的數字范圍為40-47,代碼如下。
echo -e “\033[40;37m 黑底白字\033[0m” #<==40m表示黑色背景。
echo -e “\033[41;37m 紅底白\033[0m” #<==41m表示紅色背景。
echo -e “\033[42;37m 綠底白字\033[0m” #<==42m表示綠色背景。
echo -e “\033[43;37m 棕底白字\033[0m” #<==43m表示棕色背景(brown),和黃色背景相近。
echo -e “\033[44;37m 藍底白字\033[0m” #<==44m表示藍色背景。
echo -e “\033[45;37m 洋紅底白字\033[0m” #<==45m表示洋紅色背景(magenta),和紫色背景相近。
echo -e “\033[46;37m 藍綠底白字\033[0m” #<==46m表示藍綠色背景(cyan),和淺藍色背景相近。
echo -e “\033[47;30m 白底黑字\033[0m” #<==47m表示白色背景。
最后面控制選項說明
\033[0m 關閉所有屬性
\033[1m 設置高亮度
\033[4m 下劃線
\033[5m 閃爍
\033[7m 反顯
\033[8m 消隱
\033[30m — \33[37m
設置前景色
\033[40m — \33[47m 設置背景色
\033[nA 光標上移n行
\033[nB 光標下移n行
\033[nC 光標右移n行
\033[nD 光標左移n行
\033[y;xH設置光標位置
\033[2J 清屏
\033[K 清除從光標到行尾的內容
\33[s 保存光標位置
\033[u 恢復光標位置
\033[?25l 隱藏光標
\033[?25h 顯示光標
總結
以上是生活随笔為你收集整理的shell编程快速入门(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 万字干货 | 用游戏高手的用户洞察法,如
- 下一篇: 6.2自旋锁