什么是shell腳本,其實,shell腳本就是利用shell的功能所寫的一個程序,這個程序是使用純文本文件,將一些shell的語法與命令(包含外部命令)寫在里面,搭配正則表達式、管道命令與數據流重定向等功能等這些命令的組合起來,以達到我們所想要的目的。
程序編程風格有兩種:
過程式:以指令為中心,數據服務于指令。
對象式:以數據為中心,指令服務于數據。
過程式編程有 順序執行、循環執行、選擇執行。
shel程序就是過程式式的解釋器,提供編程能力,然后解釋執行。
shell腳本編寫要注意一下事項:
1、命令的執行時由上而下、從左到右執行的。
2、命令、參數間的多個空白會被忽略。
3、如果讀取到空白符(Enter),就嘗試執行該命令。
4、如果一行內容太多可以用\[Enter]換行編寫
5、"#"作為注釋,任何加在#后面的數據將會被忽略為注釋。
創建腳本
1、第一行必須用#!/bin/bash來聲明這個腳本的shell名稱
2、第二行一下可以用#來注釋shell腳本的內容、功能、信息版本和作者和聯系方式、建立日期、歷史記錄等良好習慣。有助于將來的拍錯。 好記性不如爛筆頭!
3、建議將一些重要的環境變量設置好,如此一來,就可以直接使用外部命令,而不必寫絕對路徑。
4、然后就將主要的程序寫好輸出
可以下用下面的命令來校驗腳本
bash -n /path/to/some_script
檢測腳本中的語法錯誤
?bash -x /path/to/some_script
調試執行
bash變量
那么什么變量呢?額,簡單的說變量就是用一個簡單特定的字符來代替另一個比較復雜或者是容易變動的數據。
變量類型
變量類型的作用有
1、數據存儲格式
2、參與的運算
3、表示的數據范圍
變量的類型有:字符型、數值型。 數值型分為:整型和浮點型
變量對于編程語言來講分為強類型和弱類型
強類型:定義變量時必須指定類型、參與運算必須符合類型要求;調用未聲明變量會產生錯誤
弱類型:無須指定類型,默認均為字符型;參與運算會自動進行隱式類型轉換;變量無須事先定義可直接調用。 shell為弱類型
變量命名法則:
1、不能使程序中的保留字:例如if, for;
2、只能使用數字、字母及下劃線,且不能以數字開頭
3、見名知義
4、統一命名規則:駝峰命名法
變量與變量的內容以一個等號"="來連接
例如 first_Name=Alan
等號兩邊不能直接接空格符。若使用空格符可以用雙引號即弱引用( " )或單引號即強引用( ' )將變量結合起來
當時雙引號內的特殊符號如"$",可以保留原本的特性
var="lang is $LANG" 則echo顯示為"lang is en_US.UTF-8
單引號內的特殊符號僅為純文本字符如
var='lang is $LANG' 則echo顯示為"lang is $LANG"
可用轉義字符"\"將特殊符號變成一般符號如($、\、空格符、!等)
根據變量的生效范圍可分為
本地變量:生效范圍為當前shell進程;對當前shell之外的其它shell進程,包括當前shell的子shell進程均無效
環境變量:生效范圍為當前shell進程及其子進程
局部變量:生效范圍為當前shell進程中某代碼片斷(通常指函數)
位置變量:$1, $2, …來表示,用于讓腳本在腳本代碼中調用通過命令行傳遞給它的參數
特殊變量:$?, $0, $*, $@, $#
本地變量賦值:name=‘value’,
?可以使用引用value:
(1) 可以是直接字串; name=“root"
(2) 變量引用:name="$USER"
(3) 命令引用:name=`COMMAND`, name=$(COMMAND)
變量引用:${name}, $name 也可以累加
例如: PATH=$PATH:~/bin: 累加~/bin到原有的PATH變量中
[root@localhost bin]# echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin:usr/local/bin:/usr/local/sbin:/root/bin:/root/bin:
"":弱引用,其中的變量引用會被替換為變量值
'':強引用,其中的變量引用不會被替換為變量值,而保持原字符串
單引號和雙引號最大不同之處在于雙引號仍然可以保有變量的內容,但單引號內僅能是一般字符,而不會有特殊符號。
顯示已定義的所有變量(包括環境變量):set
刪除變量:unset name
環境變量
變量聲明、賦值:
export name=VALUE
export也可以把本地變量轉換環境變量
declare -x name=VALUE
?變量引用:$name, ${name}
?顯示所有環境變量:
export
env
printenv
刪除:unset name
bash有許多內建的環境變量:PATH, SHELL, HOME等用大寫字母來定義環境變量。
只讀變量:只能聲時,但不能修改和刪除
readonlyname
declare -r name
位置變量:在腳本代碼中調用通過命令行傳遞給腳本的參數
$1, $2, …:對應第1、第2等參數,shift [n]換位置
$0: 命令本身
$*: 傳遞給腳本的所有參數,全部參數合為一個字符串
$@: 傳遞給腳本的所有參數,每個參數為獨立字符串
$#: 傳遞給腳本的參數的個數
$@ $* 只在被雙引號包起來的時候才會有差異
bash中的算術運算:help let
+, -, *, /, %取模(取余), **(乘方)
實現算術運算:
(1) let var=算術表達式
(2) var=$[算術表達式]
(3) var=$((算術表達式))
(4) var=$(expr arg1 arg2 arg3 …)
(5) declare –ivar= 數值
(6) echo ‘算術表達式’ | bc
增強型賦值:
+=, -=, *=, /=, %=
?let varOPERvalue
例如:let count+=3
自加3后自賦值
?自增,自減:
let var+=1
let var++
let var-=1
let var–
邏輯運算又稱布爾運算 布爾用數學方法研究邏輯問題,成功地建立了邏輯演算。他用等式表示判斷,把推理看作等式的變換。
這種變換的有效性不依賴人們對符號的解釋,只依賴于符號的組合規律 。 true作1 false作0 與運算用& 或運算用||
與運算:
1 && 1 = 1 真
1 && 0 = 0 假
0 && 1 = 0 假
0 && 0 = 0 假
或運算:
1 || 1 = 1 真
1 || 0 = 1 真
0 || 0 = 1 真
0 || 0 = 0 假
非:!
! 1 = 0
! 0 = 1
?短路運算:
短路與:
第一個為0,結果必定為0;
第一個為1,第二個必須要參與運算;
短路或:
第一個為1,結果必定為1;
第一個為0,第二個必須要參與運算;
?異或:^
異或的兩個值,相同為假,不同為真
進程使用退出狀態來報告成功或失敗
0 代表成功,1-255代表失敗
$? 變量保存最近的命令退出狀態
例如:
ping-c1-W1hostdown&>/dev/null
echo$?
bash自定義退出狀態碼
exit [n]:自定義退出狀態碼;
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決于exit命令后面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決于腳本中執行的最后一條命令的狀態碼
判斷某需求是否滿足,需要由測試機制來實現;
專用的測試表達式需要由測試命令輔助完成測試過程;
?評估布爾聲明,以便用在條件性執行中
?若真,則返回0
?若假,則返回1
?測試命令:
?test EXPRESSION
?[ EXPRESSION ]
?[[ EXPRESSION ]]
注意:EXPRESSION前后必須有空白字符
根據退出狀態而定,命令可以有條件地運行
&& 代表條件性的AND THEN
|| 代表條件性的OR ELSE
?例如:ls /dev && echo "This is device file"
ls /tmp/cpwd|| mkdir /tmp/cpwd
ls /dev/abc && echo "exist" || echo "no exist"
test命令是shell環境中測試條件表達式的實用工具
-b<文件>:如果文件為一個塊特殊文件,則為真;
-c<文件>:如果文件為一個字符特殊文件,則為真;
-d<文件>:如果文件為一個目錄,則為真;(常用)
-e<文件>:如果文件存在,則為真;(常用)
-f<文件>:如果文件為一個普通文件,則為真;(常用)
-g<文件>:如果設置了文件的SGID位,則為真;
-G<文件>:如果文件存在且歸該組所有,則為真;
-k<文件>:如果設置了文件的粘著位,則為真;
-O<文件>:如果文件存在并且歸該用戶所有,則為真;
-p<文件>:如果文件為一個命名管道,則為真;
-r<文件>:如果文件可讀,則為真;
-s<文件>:如果文件的長度不為零,則為真;
-S<文件>:如果文件為一個套接字特殊文件,則為真;
-u<文件>:如果設置了文件的SUID位,則為真;
-w<文件>:如果文件可寫,則為真;
-x<文件>:如果文件可執行,則為真。
兩種文件之間的比較 如 test file1 -nt file2
-nt file1 -nt file2 判斷file1是否比file2新(newer than)
-ot file1 -ot file2 判斷file1是否比file2舊(older than)
-er file1 -er file2 判斷file1和file2為同一文件 (inode相同的文件)
兩個整數之間的判斷,例如 test file -eq file1
-eq 兩數值相等(equal)
-ne 兩數值不相等(not equal)
-gt file1大于file2(greater than)
-lt file1小于fiel2(less than)
-ge file1大于等于file2(greater than or equal)
-le file1小于等于file2(less than or equal)
判斷字符串的數據
字符串測試:
==:是否等于;
>: ascii碼是否大于ascii碼
<: 是否小于
!=: 是否不等于
=~: 左側字符串是否能夠被右側的PATTERN所匹配
注意: 此表達式一般用于[[ ]]中;
test -z string 判斷字符串是否為0,若string為空字符串,則為真
test -n string 判斷字符串是否為非0,若string為空字符串,則為假
組合測試條件
?第一種方式:
COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如:[ -e FILE ] && [ -r FILE ]
?第二種方式:
EXPRESSION1 -a EXPRESSION2 并且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
必須使用測試命令進行;
[ -z “$HOSTNAME” -o $HOSTNAME "=="localhost.localdomain" ] && hsotname.alan
[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
read命令從鍵盤讀取變量的值,通常用在shell腳本中與用戶進行交互的場合。該命令可以一次讀取多個變量的值,變量和輸入的值都需要使用空格隔開。在read命令后面,如果沒有指定變量名,讀取的數據將被自動賦值給特定的變量REPLY
-p:指定讀取值時的提示符; -t:指定讀取值時等待的時間(秒)。
read -p “Enter a filename:“ FILE
作業
1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。
[root@localhost work]# cat systeminfo.sh #!/bin/bash # #編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息, 包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。 I_p=$(ifconfig|grep -A 1 '^e.*[^[:space:]]\+'|tr -s ' '|cut -d' ' -f3|tr -sc [[:digit:].] ' ') C_pu=$(lscpu|grep 'Model name'|tr -s ' '|cut -d' ' -f3-) M_em=$(grep 'MemTotal' /proc/meminfo) H_ard=$(fdisk -l|grep '/dev/sda\>'|tr -s ' '|cut -d' ' -f3-4) echo -e "hostname:\033[31m ${hostname} \033[0m" echo -e "ipaddress is:\033[31m${I_p} \033[0m" echo -e "OS is:\033[31m$(cat /etc/redhat-release)\033[0m" echo -e "kernet is:\033[31m$(uname -r)\033[0m" echo -e "CPU tpye is:\033[31m${C_pu}\033[0m" echo -e "Mem size is\033[31m${M_em}\033[0m" echo -e "hardwqre size is:\033[31m${H_ard}\033[0m" [root@localhost work]# ./systeminfo.sh hostname: ipaddress is: 10.1.36.6 192.168.200.6 OS is:CentOS release 6.8 (Final) kernet is:2.6.32-642.el6.x86_64 CPU tpye is:Intel(R) Celeron(R) CPU N2940 @ 1.83GHz Mem size isMemTotal: 1906276 kB hardwqre size is:214.7 GB
2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
#!/bin/bash #編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中 back_up=$(cp -r /etc /root/etc`date +%F`) echo -e "backup /etc directory:\033[31m${back_up}\033[0m" [root@localhost work]# ./backup.sh #腳本執行 backup /etc directory: [root@localhost work]# ll -d /etc/ /root/etc2016-08-14 #查看備份是否成功 drwxr-xr-x. 102 root root 12288 Aug 16 13:33 /etc/ drwxr-xr-x 102 root root 12288 Aug 14 19:36 /root/etc2016-08-14
3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
[root@localhost work]# cat disk.sh #!/bin/bash # #編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值 disk_d=$(df |tr -s ' '|cut -d" " -f5|tr -d "%"|sort -n|tail -1) echo "disk:${disk_d}" [root@localhost work]# ./disk.sh #腳本執行 disk:22
4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序
[root@localhost work]# cat link.sh #!/bin/bash #編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序 L_ink=$(netstat -nt|tr -s ":" ' '|cut -d" " -f4|grep '[[:digit:].]'|sort -nr|uniq -c) echo "ipddress is:${L_ink}" [root@localhost work]# ./link.sh #腳本執行 ipddress is: 2 192.168.200.6
5、寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
[root@localhost work]# cat sumid.sh #!/bin/bash #寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和 u_id1=$(head -10 /etc/passwd|tail -1|cut -d: -f3) u_id2=$(head -20 /etc/passwd|tail -1|cut -d: -f3) let sum=$u_id1+$u_id2 echo "$sum" [root@localhost work]# ./sumid.sh #腳本執行結果 42
6、寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
[root@localhost work]# cat sumspace.sh #!/bin/bash #寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和 space1=$(grep "^[[:space:]]*$" $1 |wc -l) space2=$(grep "^[[:space:]]*$" $2 |wc -l) let space=$space1+$space2 echo "$space" [root@localhost work]# ./sumspace.sh /etc/fstab /etc/rc.d/init.d/functions#執行腳本 107
7、寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
[root@localhost work]# cat sumfile.sh #!/bin/bash #寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件 one=`ls -A /etc|wc -l` two=`ls -A /var|wc -l` three=`ls -A /usr|wc -l` let all=$one+$two+$three echo "all line is$all" [root@localhost work]# ./sumfile.sh #腳本執行 all line is264
7、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
[root@localhost work]# cat argsnum.sh #!/bin/bash #寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1, #則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1, #則顯示第一個參數所指向的文件中的空白行數 rgum=`[ $# -le 1 ] && echo "At least one path" && exit 0 || grep '^[[:space:]]*$' $1 |wc -l` echo "$rgum" [root@localhost work]# sh argsnum.sh /etc/fstab #一個參數 At least one path [root@localhost work]# sh argsnum.sh /etc/fstab /etc/passwd #2個參數 1
原創文章,作者:ladsdm,如若轉載,請注明出處:http://www.www58058.com/36561