? ? Shell概述
Shell是一種具備特殊功能的程序,它提供了用戶與內(nèi)核進(jìn)行交互操作的一種接口。它接收用戶輸入的命令,并把它送入內(nèi)核去執(zhí)行。內(nèi)核是Linux系統(tǒng)的心臟,從開(kāi)機(jī)自檢就駐留在計(jì)算機(jī)的內(nèi)存中,直到計(jì)算機(jī)關(guān)閉為止,而用戶的應(yīng)用程序存儲(chǔ)在計(jì)算機(jī)的硬盤(pán)上,僅當(dāng)需要時(shí)才被調(diào)入內(nèi)存。Shell是一種應(yīng)用程序,當(dāng)用戶登錄Linux系統(tǒng)時(shí),Shell就會(huì)被調(diào)入內(nèi)存去執(zhí)行。Shell獨(dú)立于內(nèi)核,它是連接內(nèi)核和應(yīng)用程序的橋梁,并由輸入設(shè)備讀取命令,再將其轉(zhuǎn)為計(jì)算機(jī)可以理解的機(jī)械碼,Linux內(nèi)核才能執(zhí)行該命令。
優(yōu)勢(shì)
Shell腳本語(yǔ)言的好處是簡(jiǎn)單、易學(xué)、易用,適合處理文件和目錄之類的對(duì)象,以簡(jiǎn)單的方式快速完成某些復(fù)雜的事情通常是創(chuàng)建腳本的重要原則,腳本語(yǔ)言的特性可以總結(jié)為以下幾個(gè)方面:
語(yǔ)法和結(jié)構(gòu)通常比較簡(jiǎn)單。
學(xué)習(xí)和使用通常比較簡(jiǎn)單,
通常以容易修改程序的“解釋”作為運(yùn)行方式,而不需要“編譯。
程序的開(kāi)發(fā)產(chǎn)能優(yōu)于運(yùn)行效能。
Shell腳本語(yǔ)言是Linux/Unix系統(tǒng)上一種重要的腳本語(yǔ)言,在Linux/Unix領(lǐng)域應(yīng)用極為廣泛,熟練掌握Shell腳本語(yǔ)言是一個(gè)優(yōu)秀的Linux/Unix開(kāi)發(fā)者和系統(tǒng)管理員必經(jīng)之路。利用Shell腳本語(yǔ)言可以簡(jiǎn)潔地實(shí)現(xiàn)復(fù)雜的操作,而且Shell腳本程序往往可以在不同版本的Linux/Unix系統(tǒng)上通用。
Shell編程
基本格式
Shell腳本的文件名后綴通常是.sh (當(dāng)然你也可以使用其他后綴或者沒(méi)有后綴,.sh是為了規(guī)范)
程序編寫(xiě)格式:
[java] view plain copy#!/bin/bash
# 注釋使用#號(hào)
代碼示例:
[java] view plain copy//使用vi編輯器編寫(xiě)shell腳本(a.sh不存在則會(huì)新建)
vi a.sh
進(jìn)入vi編輯模式后編寫(xiě)執(zhí)行代碼
?。踛ava] view plain copy//固定格式,記住就可以了
#!/bin/bash
//執(zhí)行的代碼
echo Hello World
賦予權(quán)限并執(zhí)行:
?。踛ava] view plain copy//賦予可執(zhí)行權(quán)限
chmod +x a.sh
//執(zhí)行(調(diào)用/bin/bash執(zhí)行a.sh腳本)
。/a.sh
執(zhí)行結(jié)果:
下面是幾種運(yùn)行情況:
?。踛ava] view plain copya.sh
這樣的話需要保證腳本具有執(zhí)行權(quán)限并且在環(huán)境變量PATH中有(。),這樣在執(zhí)行的時(shí)候會(huì)先從當(dāng)前目錄查找。
[java] view plain copy./a.sh
只要保證這個(gè)腳本具有執(zhí)行權(quán)限即可
?。踛ava] view plain copy/usr/local/a.sh
只要保證這個(gè)腳本具有執(zhí)行權(quán)限即可
?。踛ava] view plain copybash a.sh
直接可以執(zhí)行,甚至這個(gè)腳本文件中的第一行都可以不引入/bin/bash,它是將hello.sh作為參數(shù)傳給bash命令來(lái)執(zhí)行的。
?。踛ava] view plain copybash -x /path/to/aa.sh
bash的單步執(zhí)行
[java] view plain copybash -n /path/to/aa.sh
bash語(yǔ)法檢查
變量
變量不需要聲明,初始化不需要指定類型
變量命名
1、只能使用數(shù)字,字母和下劃線,且不能以數(shù)字開(kāi)頭
2、變量名區(qū)分大小寫(xiě)
3、建議命令要通俗易懂
注意:變量賦值是通過(guò)等號(hào)(=)進(jìn)行賦值,在變量、等號(hào)和值之間不能出現(xiàn)空格。
顯示變量值使用echo命令(類似于java中的system.out) ,加上$變量名,也可以使用${變量名}
例如:
[java] view plain copyecho $JAVA_HOME
echo ${JAVA_HOME}
變量的申明和使用:
變量分類:
Shell變量有這幾類:本地變量、環(huán)境變量、局部變量、位置變量、特殊變量。
本地變量:
只對(duì)當(dāng)前shell進(jìn)程有效的,對(duì)當(dāng)前進(jìn)程的子進(jìn)程和其它shell進(jìn)程無(wú)效。
定義:VAR_NAME=VALUE
變量引用:${VAR_NAME} 或者 $VAR_NAME
取消變量:unset VAR_NAME
相當(dāng)于java中的私有變量(private),只能當(dāng)前類使用,子類和其他類都無(wú)法使用。
比如在一個(gè)bash命令窗口下再使用bash,則變成了子進(jìn)程,本地變量不會(huì)被這個(gè)子進(jìn)程所訪問(wèn)。
環(huán)境變量:
自定義的環(huán)境變量對(duì)當(dāng)前shell進(jìn)程及其子shell進(jìn)程有效,對(duì)其它的shell進(jìn)程無(wú)效
定義:export VAR_NAME=VALUE
對(duì)所有shell進(jìn)程都有效需要配置到配置文件中
[java] view plain copyvi /etc/profile
source /etc/profile
相當(dāng)于java中的protected修飾符,對(duì)當(dāng)前類,子孫類,以及同一個(gè)包下面可以共用。
和windows中的環(huán)境變量比較類似
自定義的環(huán)境變量:
局部變量:
在函數(shù)中調(diào)用,函數(shù)執(zhí)行結(jié)束,變量就會(huì)消失
對(duì)shell腳本中某代碼片段有效
定義:local VAR_NAME=VALUE
相當(dāng)于java代碼中某一個(gè)方法中定義的局部變量,只對(duì)這個(gè)方法有效。
位置變量:
比如腳本中的參數(shù):
$0:腳本自身
$1:腳本的第一個(gè)參數(shù)
$2:腳本的第二個(gè)參數(shù)
相當(dāng)于java中main函數(shù)中的args參數(shù),可以獲取外部參數(shù)。
特殊變量:
$?:接收上一條命令的返回狀態(tài)碼
返回狀態(tài)碼在0-255之間
$#:參數(shù)個(gè)數(shù)
$*:或者$@:所有的參數(shù)
$$:獲取當(dāng)前shell的進(jìn)程號(hào)(PID)(可以實(shí)現(xiàn)腳本自殺)(或者使用exit命令直接退出也可以使用exit [num])
引號(hào)
Shell編程中有三類引號(hào):?jiǎn)我?hào)、雙引號(hào)、反引號(hào)。
‘’單引號(hào)不解析變量
?。踛ava] view plain copyecho ‘$name’
“”雙引號(hào)會(huì)解析變量
[java] view plain copyecho “$name”
``反引號(hào)是執(zhí)行并引用一個(gè)命令的執(zhí)行結(jié)果,類似于$(。。。)
[java] view plain copyecho `$name`
示例:
循環(huán)
for循環(huán)
通過(guò)使用一個(gè)變量去遍歷給定列表中的每個(gè)元素,在每次變量賦值時(shí)執(zhí)行一次循環(huán)體,直至賦值完成所有元素退出循環(huán)
格式1
?。踛ava] view plain copyfor ((i=0;i《10;i++))
do
。。。
Done
格式2
?。踛ava] view plain copyfor i in 0 1 2 3 4 5 6 7 8 9
do
。。。
Done
格式3
?。踛ava] view plain copyfor i in {0..9}
do
。。。
done
注意:for i in {0..9} 等于for i in {0..9..1} , 第三個(gè)參數(shù)為跨步。
例如:
{0..9..2} 表示 0,2,4,6,8
while循環(huán)
適用于循環(huán)次數(shù)未知,或不便用for直接生成較大的列表時(shí)
格式:
?。踛ava] view plain copywhile 測(cè)試條件
do
循環(huán)體
done
如果測(cè)試條件為“真”,則進(jìn)入循環(huán),測(cè)試條件為假,則退出循環(huán)。
打印結(jié)果為0~9.
循環(huán)控制
循環(huán)控制命令——break
break命令是在處理過(guò)程中跳出循環(huán)的一種簡(jiǎn)單方法,可以使用break命令退出任何類型的循環(huán),包括while循環(huán)和for循環(huán)
循環(huán)控制命令——continue
continue命令是一種提前停止循環(huán)內(nèi)命令,而不完全終止循環(huán)的方法,這就需要在循環(huán)內(nèi)設(shè)置shell不執(zhí)行命令的條件
條件
bash條件測(cè)試
格式:
[java] view plain copytest EXPR
?。?EXPR ]:注意中括號(hào)和表達(dá)式之間的空格
整型測(cè)試:
-gt:大于:
-lt:小于
-ge:大于等于
-le:小于等于
-eq:等于
-ne:不等于
例如[ $num1 -gt $num2 ]或者test $num1 -gt $num2
字符串測(cè)試:
=:等于,例如判斷變量是否為空 [ “$str” = “” ] 或者[ -z $str ]
??!=:不等于
判斷
if判斷:
單分支
?。踛ava] view plain copy if 測(cè)試條件;then
選擇分支
fi
雙分支
?。踛ava] view plain copyif 測(cè)試條件
then
選擇分支1
else
選擇分支2
fi
多分支
?。踛ava] view plain copyif 條件1; then
分支1
elif 條件2; then
分支2
elif 條件3; then
分支3
。。。
else
分支n
i
雙分支示例:
Case判斷
有多個(gè)測(cè)試條件時(shí),case語(yǔ)句會(huì)使得語(yǔ)法結(jié)構(gòu)更清晰
格式:
?。踛ava] view plain copycase 變量引用 in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
。。。
*)
分支n
;;
esac
PATTERN :類同于文件名通配機(jī)制,但支持使用|表示或者
a|b:a或者b
*:匹配任意長(zhǎng)度的任意字符
???:匹配任意單個(gè)字符
?。踑-z]:指定范圍內(nèi)的任意單個(gè)字符
示例:
算術(shù)運(yùn)算
?。踛ava] view plain copylet varName=算術(shù)表達(dá)式
varName=$[算術(shù)表達(dá)式]
varName=$((算術(shù)表達(dá)式))
varName=`expr $num1 + $num2`
使用這種格式要注意兩個(gè)數(shù)字和+號(hào)中間要有空格。
示例:
邏輯運(yùn)算符
if [ 條件A && 條件B ] 在shell中怎么寫(xiě)?
if [ 條件A && 條件B ];then 是不對(duì)的
解決方法:
(1)需要用到shell中的邏輯操作符
-a 與
-o 或
??! 非
如if [ 條件A -a 條件B ]
?。?)if [ 條件A ] && [條件B ]
(3)if((A&&B))
?。?)if [[ A&&B ]]
自定義函數(shù)
格式:
[java] view plain copyfunction 函數(shù)名(){
。。。
}
引用自定義函數(shù)文件時(shí),使用source func.sh
有利于代碼的重用性
函數(shù)傳遞參數(shù)(可以使用類似于Java中的args,args[1]代表Shell中的$1)
函數(shù)的返回值,只能是數(shù)字
read
read命令接收標(biāo)準(zhǔn)輸入(鍵盤(pán))的輸入,或者其他文件描述符的輸入。得到輸入后,read命令將數(shù)據(jù)放入一個(gè)標(biāo)準(zhǔn)變量中。
格式
?。踛ava] view plain copyread VAR_NAME
read如果后面不指定變量,那么read命令會(huì)將接收到的數(shù)據(jù)放置在環(huán)境變量REPLY中
?。踛ava] view plain copy#表示輸入時(shí)的提示字符串:
read -p “Enter your name:” VAR_NAME
?。踛ava] view plain copy# -t表示輸入等待的時(shí)間
read -t 5 -p “enter your name:” VAR_NAME
[java] view plain copy# -s 表示安全輸入,鍵入密碼時(shí)不會(huì)顯示
read -s -p “Enter your password: ” pass
declare
用來(lái)限定變量的屬性
-r 只讀
-i 整數(shù):某些算術(shù)計(jì)算允許在被聲明為整數(shù)的變量中完成,而不需要特別使用expr或let來(lái)完成。
-a 數(shù)組
示例:
字符串操作
獲取長(zhǎng)度:
?。踛ava] view plain copy${#VAR_NAME}
字符串截取
[java] view plain copy${variable:offset:length}或者${variable:offset}
取尾部的指定個(gè)數(shù)的字符
?。踛ava] view plain copy${variable: -length}:注意冒號(hào)后面有空格
大小寫(xiě)轉(zhuǎn)換
小--》大:
[java] view plain copy${variable^^}
大--》?。?/p>
[java] view plain copy${variable,,}
示例:
數(shù)組
定義:declare -a:表示定義普通數(shù)組
特點(diǎn)
支持稀疏格式
僅支持一維數(shù)組
數(shù)組賦值方式
一次對(duì)一個(gè)元素賦值a[0]=$RANDOM
一次對(duì)多個(gè)元素賦值a=(a b c d)
按索引進(jìn)行賦值a=([0]=a [3]=b [1]=c)
使用read命令read -a ARRAY_NAME查看元素
[java] view plain copy${ARRAY[index]}:查看數(shù)組指定角標(biāo)的元素
${ARRAY}:查看數(shù)組的第一個(gè)元素
${ARRAY[*]}或者${ARRAY[@]}:查看數(shù)組的所有元素
獲取數(shù)組的長(zhǎng)度
[java] view plain copy${#ARRAY[*]}
${#ARRAY[@]}
獲取數(shù)組內(nèi)元素的長(zhǎng)度
?。踛ava] view plain copy${#ARRAY[0]}
注意:${#ARRAY[0]}表示獲取數(shù)組中的第一個(gè)元素的長(zhǎng)度,等于${#ARRAY}
從數(shù)組中獲取某一片段之內(nèi)的元素(操作類似于字符串操作)
格式:
?。踛ava] view plain copy${ARRAY[@]:offset:length}
offset:偏移的元素個(gè)數(shù)
length:取出的元素的個(gè)數(shù)
${ARRAY[@]:offset:length}:取出偏移量后的指定個(gè)數(shù)的元素
${ARRAY[@]:offset}:取出數(shù)組中偏移量后的所有元素
數(shù)組刪除元素:
?。踛ava] view plain copyunset ARRAY[index]
示例:
其他命令
date
顯示當(dāng)前時(shí)間
格式化輸出 +%Y-%m-%d
格式%s表示自1970-01-01 00:00:00以來(lái)的秒數(shù)
指定時(shí)間輸出 --date=‘2009-01-01 11:11:11’
指定時(shí)間輸出 --date=‘3 days ago’ (3天之前,3天之后可以用-3)
示例:
后臺(tái)運(yùn)行腳本
在腳本后面加一個(gè)&
?。踛ava] view plain copytest.sh &
這樣的話雖然可以在后臺(tái)運(yùn)行,但是當(dāng)用戶注銷(logout)或者網(wǎng)絡(luò)斷開(kāi)時(shí),終端會(huì)收到Linux HUP信號(hào)(hangup)信號(hào)從而關(guān)閉其所有子進(jìn)程
nohup命令
不掛斷的運(yùn)行命令,忽略所有掛斷(hangup)信號(hào)
?。踛ava] view plain copynohup test.sh &
nohup會(huì)忽略進(jìn)程的hangup掛斷信號(hào),所以關(guān)閉當(dāng)前會(huì)話窗口不會(huì)停止這個(gè)進(jìn)程的執(zhí)行。
nohup會(huì)在當(dāng)前執(zhí)行的目錄生成一個(gè)nohup.out日志文件
標(biāo)準(zhǔn)輸入、輸出、錯(cuò)誤、重定向
標(biāo)準(zhǔn)輸入、輸出、錯(cuò)誤可以使用文件描述符0、1、2引用
使用重定向可以把信息重定向到其他位置
ls 》file 或者 ls 1》file(ls 》》file)
lk 2》file(lk是一個(gè)錯(cuò)誤命令)
ls 》file 2》&1
ls 》 /dev/null(把輸出信息重定向到無(wú)底洞)
例子:
?。踛ava] view plain copycommand 》/dev/null 2》&1
Crontab定時(shí)器
linux下的定時(shí)任務(wù)
編輯使用crontab -e
一共6列,分別是:分 時(shí) 日 月 周 命令
查看crontab執(zhí)行日志
?。踛ava] view plain copytail -f /var/log/cron
必須打開(kāi)rsyslog服務(wù)cron文件中才會(huì)有執(zhí)行日志(service rsyslog status)
?。踛ava] view plain copytail -f /var/spool/mail/root(查看crontab最近的執(zhí)行情況)
查看cron服務(wù)狀態(tài)
?。踛ava] view plain copyservice crond status
啟動(dòng)cron服務(wù)
?。踛ava] view plain copyservice crond start
小結(jié)及示例:
基本格式 :
* * * * * command
分 時(shí) 日 月 周 命令
第1列表示分鐘1~59 每分鐘用*或者 */1表示
第2列表示小時(shí)1~23(0表示0點(diǎn))
第3列表示日期1~31
第4列表示月份1~12
第5列標(biāo)識(shí)號(hào)星期0~6(0表示星期天)
第6列要運(yùn)行的命令
crontab文件的一些例子:
30 21 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每晚的21:30重啟apache。
45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每月1、10、22日的4 : 45重啟apache。
10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每周六、周日的1 : 10重啟apache。
0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示在每天18 : 00至23 : 00之間每隔30分鐘重啟apache。
0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每星期六的11 : 00 pm重啟apache。
* */1 * * * /usr/local/etc/rc.d/lighttpd restart
每一小時(shí)重啟apache
* 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
晚上11點(diǎn)到早上7點(diǎn)之間,每隔一小時(shí)重啟apache
0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
每月的4號(hào)與每周一到周三的11點(diǎn)重啟apache
0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
一月一號(hào)的4點(diǎn)重啟apache
ps和jps
ps:用來(lái)顯示進(jìn)程的相關(guān)信息
ps顯示當(dāng)前shell啟動(dòng)的所有進(jìn)程
ps -e顯示系統(tǒng)中所有進(jìn)程
ps -ef|grep java
jps:類似linux的ps命令,不同的是ps是用來(lái)顯示所有進(jìn)程,而jps只顯示java進(jìn)程,準(zhǔn)確的說(shuō)是顯示當(dāng)前用戶已啟動(dòng)的部分java進(jìn)程信息,信息包括進(jìn)程號(hào)和簡(jiǎn)短的進(jìn)程command。
問(wèn)題:某個(gè)java進(jìn)程已經(jīng)啟動(dòng),用jps卻顯示不了該進(jìn)程進(jìn)程號(hào),使用ps -ef|grep java卻可以看到?
java程序啟動(dòng)后,默認(rèn)(請(qǐng)注意是默認(rèn))會(huì)在/tmp/hsperfdata_userName目錄下以該進(jìn)程的id為文件名新建文件,并在該文件中存儲(chǔ)jvm運(yùn)行的相關(guān)信息,其中的userName為當(dāng)前的用戶名,/tmp/hsperfdata_userName目錄會(huì)存放該用戶所有已經(jīng)啟動(dòng)的java進(jìn)程信息。而jps、jconsole、jvisualvm等工具的數(shù)據(jù)來(lái)源就是這個(gè)文件(/tmp/hsperfdata_userName/pid)。所以當(dāng)該文件不存在或是無(wú)法讀取時(shí)就會(huì)出現(xiàn)jps無(wú)法查看該進(jìn)程號(hào)。
原因:1,磁盤(pán)讀寫(xiě)、目錄權(quán)限問(wèn)題。2,臨時(shí)文件丟失,被刪除或是定期清理。3,java進(jìn)程信息文件存儲(chǔ)地址被設(shè)置,不在/tmp目錄下
登錄Shell和交互shell
交互式的:顧名思義,這種shell中的命令時(shí)由用戶從鍵盤(pán)交互式地輸入的,運(yùn)行的結(jié)果也能夠輸出到終端顯示給用戶看。
非交互式的:這種shell可能由某些自動(dòng)化過(guò)程啟動(dòng),不能直接從請(qǐng)求用戶的輸入,也不能直接輸出結(jié)果給終端用戶看。輸出最好寫(xiě)到文件。比如使用Shell腳本。
登錄式:意思是這種是在某用戶由/bin/login登陸進(jìn)系統(tǒng)后啟動(dòng)的shell,跟這個(gè)用戶綁定。這個(gè)shell是用戶登陸后啟動(dòng)的第一個(gè)進(jìn)程。login進(jìn)程在啟動(dòng)shell時(shí)傳遞第0個(gè)參數(shù)指明shell的名字,該參數(shù)第一個(gè)字符為“-”,指明這是一個(gè)login shell。比如對(duì)bash而言,啟動(dòng)參數(shù)為“-bash”。
非登錄式:不需login而由某些程序啟動(dòng)的shell。傳遞給shell的參數(shù),是沒(méi)有‘-’前綴的。還以Bash為例,當(dāng)以非login方式啟動(dòng)時(shí),它會(huì)調(diào)用~/.bashrc,隨后~/.bashrc中調(diào)用/etc/bashrc,最后/etc/bashrc調(diào)用所有/etc/profile.d目錄下的腳本。
一旦打開(kāi)一個(gè)交互式login shell,或者以--login選項(xiàng)登錄的非交互式shell,都會(huì)首先加載并執(zhí)行/etc/profile中的命令,然后再依次加載~/.bash_profile, ~/.bash_login, 和~/.profile中的命令。
當(dāng)bash以login shell啟動(dòng)時(shí),它會(huì)執(zhí)行/etc/profile中的命令,然后/etc/profile調(diào)用/etc/profile.d目錄下的所有腳本;然后執(zhí)行~/.bash_profile,~/.bash_profile調(diào)用~/.bashrc,最后~/.bashrc又調(diào)用/etc/bashrc。要識(shí)別一個(gè)shell是否為login shell,只需在該shell下執(zhí)行echo $0。
注意: /etc/profile中的設(shè)置只對(duì)Login Shell生效,而crontab運(yùn)行腳本的shell環(huán)境是non-login的,不會(huì)加載/etc/profile的設(shè)置。
Shell應(yīng)用示例
根據(jù)時(shí)間創(chuàng)建文件夾
需求:創(chuàng)建10個(gè)目錄,目錄名稱以當(dāng)天時(shí)間開(kāi)頭,后面拼上目錄編碼
例如:1970-01-01_1
編寫(xiě)腳本monitor.sh
持續(xù)觀察服務(wù)器每天的運(yùn)行狀態(tài),需要結(jié)合shell腳本程序和計(jì)劃任務(wù),定期跟蹤記錄不同時(shí)段服務(wù)器的cpu負(fù)載,內(nèi)存,交換空間,磁盤(pán)使用量等信息
?。踛ava] view plain copy#!/bin/bash
#this is the second script!
day_time=`date+“%F %R”`
cpu_test=`uptime`
mem_test=`free -m | grep “mem” | awk ‘{print $2}’`
swap_test=`free -m | grep “mem” | awk ‘{print $4}’`
disk_test=`df -hT`
user_test=`last -n 10`
echo “now is $day_time”
echo “%cpu is $cpu_test”
echo “Numbet of Mem size(MB) is $mem_test”
echo “Number of swap size(MB) is $swap_test”
echo “the disk shiyong qingkuang is $disk_test”
echo “the users login qingkuang is $user_test”
設(shè)置cron任務(wù)
?。踛ava] view plain copy*/15 * * * * bash /monitor.sh
55 23 * * * tar cxf /var/log/runrec /var/log/running.today && --remove-files
SHELL編程之常用技巧
/dev和/proc目錄
dev目錄是系統(tǒng)中集中用來(lái)存放設(shè)備文件的目錄。除了設(shè)備文件以外,系統(tǒng)中也有不少特殊的功能通過(guò)設(shè)備的形式表現(xiàn)出來(lái)。設(shè)備文件是一種特殊的文件,它們實(shí)際上是驅(qū)動(dòng)程序的接口。在Linux操作系統(tǒng)中,很多設(shè)備都是通過(guò)設(shè)備文件的方式為進(jìn)程提供了輸入、輸出的調(diào)用標(biāo)準(zhǔn),這也符合UNIX的“一切皆文件”的設(shè)計(jì)原則。所以,對(duì)于設(shè)備文件來(lái)說(shuō),文件名和路徑其實(shí)都不重要,最重要的使其主設(shè)備號(hào)和輔助設(shè)備號(hào),就是用ls -l命令顯示出來(lái)的原本應(yīng)該出現(xiàn)在文件大小位置上的兩個(gè)數(shù)字,比如下面命令顯示的8和0:
[zorro@zorrozou-pc0 bash]$ ls -l /dev/sda
brw-rw---- 1 root disk 8, 0 5月 12 10:47 /dev/sda12
設(shè)備文件的主設(shè)備號(hào)對(duì)應(yīng)了這種設(shè)備所使用的驅(qū)動(dòng)是哪個(gè),而輔助設(shè)備號(hào)則表示使用同一種驅(qū)動(dòng)的設(shè)備編號(hào)。我們可以使用mknod命令手動(dòng)創(chuàng)建一個(gè)設(shè)備文件:
?。踷orro@zorrozou-pc0 bash]$ sudo mknod harddisk b 8 0
[zorro@zorrozou-pc0 bash]$ ls -l harddisk
brw-r--r-- 1 root root 8, 0 5月 18 09:49 harddisk123
這樣我們就創(chuàng)建了一個(gè)設(shè)備文件叫harddisk,實(shí)際上它跟/dev/sda是同一個(gè)設(shè)備,因?yàn)樗鼈儗?duì)應(yīng)的設(shè)備驅(qū)動(dòng)和編號(hào)都一樣。所以這個(gè)設(shè)備實(shí)際上是跟sda相同功能的設(shè)備。
系統(tǒng)還給我們提供了幾個(gè)有特殊功能的設(shè)備文件,在bash編程的時(shí)候可能會(huì)經(jīng)常用到:
/dev/null:黑洞文件??梢詫?duì)它重定向如何輸出。
/dev/zero:0發(fā)生器。可以產(chǎn)生二進(jìn)制的0,產(chǎn)生多少根使用時(shí)間長(zhǎng)度有關(guān)。我們經(jīng)常用這個(gè)文件來(lái)產(chǎn)生大文件進(jìn)行某些測(cè)試,如:
?。踷orro@zorrozou-pc0 bash]$ dd if=/dev/zero of=。/bigfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.3501 s, 3.1 GB/s1234
dd命令也是我們?cè)赽ash編程中可能會(huì)經(jīng)常使用到的命令。
/dev/random:Linux下的random文件是一個(gè)根據(jù)計(jì)算機(jī)背景噪聲而產(chǎn)生隨機(jī)數(shù)的真隨機(jī)數(shù)發(fā)生器。所以,如果容納噪聲數(shù)據(jù)的熵池空了,那么對(duì)文件的讀取會(huì)出現(xiàn)阻塞。
/dev/urandom:是一個(gè)偽隨機(jī)數(shù)發(fā)生器。實(shí)際上在Linux的視線中,urandom產(chǎn)生隨機(jī)數(shù)的方法根random一樣,只是它可以重復(fù)使用熵池中的數(shù)據(jù)。這兩個(gè)文件在不同的類unix系統(tǒng)中可能實(shí)現(xiàn)方法不同,請(qǐng)注意它們的區(qū)別。
/dev/tcp & /dev/udp:這兩個(gè)神奇的目錄為bash編程提供了一種可以進(jìn)行網(wǎng)絡(luò)編程的功能。在bash程序中使用/dev/tcp/ip/port的方式就可以創(chuàng)建一個(gè)scoket作為客戶端去連接服務(wù)端的ip:port。我們用一個(gè)檢查http協(xié)議的80端口是否打開(kāi)的例子來(lái)說(shuō)明它的使用方法:
?。踷orro@zorrozou-pc0 bash]$ cat tcp.sh
#!/bin/bash
ipaddr=127.0.0.1
port=80
if ! exec 5《》 /dev/tcp/$ipaddr/$port
then
exit 1
fi
echo -e “GET / HTTP/1.0\n” 》&5
cat 《&51234567891011121314
ipaddr的部分還可以寫(xiě)一個(gè)主機(jī)名。大家可以用此腳本分別在本機(jī)打開(kāi)web服務(wù)和不打開(kāi)的情況下分別執(zhí)行觀察是什么效果。
/proc是另一個(gè)我們經(jīng)常使用的目錄。這個(gè)目錄完全是內(nèi)核虛擬的。內(nèi)核將一些系統(tǒng)信息都放在/proc目錄下一文件和文本的方式顯示出來(lái),如:/proc/cpuinfo、/proc/meminfo。我們可以使用man 5 proc來(lái)查詢這個(gè)目錄下文件的作用。
函數(shù)和遞歸
我們已經(jīng)接觸過(guò)函數(shù)的概念了,在bash編程中,函數(shù)無(wú)非是將一串命令起了個(gè)名字,后續(xù)想要調(diào)用這一串命令就可以直接寫(xiě)函數(shù)的名字了。在語(yǔ)法上定義一個(gè)函數(shù)的方法是:
name () compound-command [redirection]
function name [()] compound-command [redirection]12
我們可以加function關(guān)鍵字顯式的定義一個(gè)函數(shù),也可以不加。函數(shù)在定義的時(shí)候可以直接在后面加上重定向的處理。這里還需要特殊說(shuō)明的是函數(shù)的參數(shù)處理和局部變量,請(qǐng)看下面腳本:
[zorro@zorrozou-pc0 bash]$ cat function.sh |awk ‘{print “\t”$0}’
#!/bin/bash
aaa=1000
arg_proc () {
echo “Function begin:”
local aaa=2000
echo $1
echo $2
echo $3
echo $*
echo $@
echo $aaa
echo “Function end!”
}
echo “Script bugin:”
echo $1
echo $2
echo $3
echo $*
echo $@
echo $aaa
arg_proc aaa bbb ccc ddd eee fff
echo $1
echo $2
echo $3
echo $*
echo $@
echo $aaa
echo “Script end!”12345678910111213141516171819202122232425262728293031323334
我們帶-x參數(shù)執(zhí)行一下:
+ aaa=1000
+ echo ‘Script bugin:’
Script bugin:
+ echo 111
111
+ echo 222
222
+ echo 333
333
+ echo 111 222 333 444 555
111 222 333 444 555
+ echo 111 222 333 444 555
111 222 333 444 555
+ echo 1000
1000
+ arg_proc aaa bbb ccc ddd eee fff
+ echo ‘Function begin:’
Function begin:
+ local aaa=2000
+ echo aaa
aaa
+ echo bbb
bbb
+ echo ccc
ccc
+ echo aaa bbb ccc ddd eee fff
aaa bbb ccc ddd eee fff
+ echo aaa bbb ccc ddd eee fff
aaa bbb ccc ddd eee fff
+ echo 2000
2000
+ echo ‘Function end!’
Function end!
+ echo 111
111
+ echo 222
222
+ echo 333
333
+ echo 111 222 333 444 555
111 222 333 444 555
+ echo 111 222 333 444 555
111 222 333 444 555
+ echo 1000
1000
+ echo ‘Script end!’
Script end!1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
觀察整個(gè)執(zhí)行過(guò)程可以發(fā)現(xiàn),函數(shù)的參數(shù)適用方法跟腳本一樣,都可以使用n、*、$@這些符號(hào)來(lái)處理。而且函數(shù)參數(shù)跟函數(shù)內(nèi)部使用local定義的局部變量效果一樣,都是只在函數(shù)內(nèi)部能看到。函數(shù)外部看不到函數(shù)里定義的局部變量,當(dāng)函數(shù)內(nèi)部的局部變量和外部的全局變量名字相同時(shí),函數(shù)內(nèi)只能取到局部變量的值。當(dāng)函數(shù)內(nèi)部沒(méi)有定義跟外部同名的局部變量的時(shí)候,函數(shù)內(nèi)部也可以看到全局變量。
bash編程支持遞歸調(diào)用函數(shù),跟其他編程語(yǔ)言不同的地方是,bash還可以遞歸的調(diào)用自身,這在某些編程場(chǎng)景下非常有用。我們先來(lái)看一個(gè)遞歸的簡(jiǎn)單例子:
[zorro@zorrozou-pc0 bash]$ cat recurse.sh
#!/bin/bash
read_dir () {
for i in $1/*
do
if [ -d $i ]
then
read_dir $i
else
echo $i
fi
done
}
read_dir $11234567891011121314151617
這個(gè)腳本可以遍歷一個(gè)目錄下所有子目錄中的非目錄文件。關(guān)于遞歸,還有一個(gè)經(jīng)典的例子,fork炸彈:
。(){ 。|.& };.1
這一堆符號(hào)看上去很令人費(fèi)解,我們來(lái)解釋一下每個(gè)符號(hào)的含義:根據(jù)函數(shù)的定義語(yǔ)法,我們知道。(){}的意思是,定義一個(gè)函數(shù)名子叫“?!薄km然系統(tǒng)中又個(gè)內(nèi)建命令也叫。,就是source命令,但是我們也知道,當(dāng)函數(shù)和內(nèi)建命令名字沖突的時(shí)候,bash首先會(huì)將名字當(dāng)成是函數(shù)來(lái)解釋。在{}包含的函數(shù)體中,使用了一個(gè)管道連接了兩個(gè)點(diǎn),這里的第一個(gè)。就是函數(shù)的遞歸調(diào)用,我們也知道了使用管道的時(shí)候會(huì)打開(kāi)一個(gè)subshell的子進(jìn)程,所以在這里面就遞歸的打開(kāi)了子進(jìn)程。{}后面的分號(hào)只表示函數(shù)定義完畢的結(jié)束符,在之后就是調(diào)用函數(shù)名執(zhí)行的。,之后函數(shù)開(kāi)始遞歸的打開(kāi)自己,去產(chǎn)生子進(jìn)程,直到系統(tǒng)崩潰為止。
bash并發(fā)編程和flock
在shell編程中,需要使用并發(fā)編程的場(chǎng)景并不多。我們倒是經(jīng)常會(huì)想要某個(gè)腳本不要同時(shí)出現(xiàn)多次同時(shí)執(zhí)行,比如放在crond中的某個(gè)周期任務(wù),如果執(zhí)行時(shí)間較長(zhǎng)以至于下次再調(diào)度的時(shí)間間隔,那么上一個(gè)還沒(méi)執(zhí)行完就可能又打開(kāi)一個(gè),這時(shí)我們會(huì)希望本次不用執(zhí)行。本質(zhì)上講,無(wú)論是只保證任何時(shí)候系統(tǒng)中只出現(xiàn)一個(gè)進(jìn)程還是多個(gè)進(jìn)程并發(fā),我們需要對(duì)進(jìn)程進(jìn)行類似的控制。因?yàn)椴l(fā)的時(shí)候也會(huì)有可能產(chǎn)生競(jìng)爭(zhēng)條件,導(dǎo)致程序出問(wèn)題。
我們先來(lái)看如何寫(xiě)一個(gè)并發(fā)的bash程序。在前文講到作業(yè)控制和wait命令使用的時(shí)候,我們就已經(jīng)寫(xiě)了一個(gè)簡(jiǎn)單的并發(fā)程序了,我們這次讓它變得復(fù)雜一點(diǎn)。我們寫(xiě)一個(gè)bash腳本,創(chuàng)建一個(gè)計(jì)數(shù)文件,并將里面的值寫(xiě)為0。然后打開(kāi)100個(gè)子進(jìn)程,每個(gè)進(jìn)程都去讀取這個(gè)計(jì)數(shù)文件的當(dāng)前值,并加1寫(xiě)回去。如果程序執(zhí)行正確,最后里面的值應(yīng)該是100,因?yàn)槊總€(gè)子進(jìn)程都會(huì)累加一個(gè)1寫(xiě)入文件,我們來(lái)試試:
?。踷orro@zorrozou-pc0 bash]$ cat racing.sh
#!/bin/bash
countfile=/tmp/count
if ! [ -f $countfile ]
then
echo 0 》 $countfile
fi
do_count () {
read count 《 $countfile
echo $((++count)) 》 $countfile
}
for i in `seq 1 100`
do
do_count &
done
wait
cat $countfile
rm $countfile12345678910111213141516171819202122232425
我們?cè)賮?lái)看看這個(gè)程序的執(zhí)行結(jié)果:
?。踷orro@zorrozou-pc0 bash]$ 。/racing.sh
26
[zorro@zorrozou-pc0 bash]$ 。/racing.sh
13
?。踷orro@zorrozou-pc0 bash]$ 。/racing.sh
34
?。踷orro@zorrozou-pc0 bash]$ 。/racing.sh
25
?。踷orro@zorrozou-pc0 bash]$ 。/racing.sh
45
?。踷orro@zorrozou-pc0 bash]$ 。/racing.sh
5123456789101112
多次執(zhí)行之后,每次得到的結(jié)果都不一樣,也沒(méi)有一次是正確的結(jié)果。這就是典型的競(jìng)爭(zhēng)條件引起的問(wèn)題。當(dāng)多個(gè)進(jìn)程并發(fā)的時(shí)候,如果使用的共享的資源,就有可能會(huì)造成這樣的問(wèn)題。這里的競(jìng)爭(zhēng)調(diào)教就是:當(dāng)某一個(gè)進(jìn)程讀出文件值為0,并加1,還沒(méi)寫(xiě)回去的時(shí)候,如果有別的進(jìn)程讀了文件,讀到的還是0。于是多個(gè)進(jìn)程會(huì)寫(xiě)1,以及其它的數(shù)字。解決共享文件的競(jìng)爭(zhēng)問(wèn)題的辦法是使用文件鎖。每個(gè)子進(jìn)程在讀取文件之前先給文件加鎖,寫(xiě)入之后解鎖,這樣臨界區(qū)代碼就可以互斥執(zhí)行了:
?。踷orro@zorrozou-pc0 bash]$ cat flock.sh
#!/bin/bash
countfile=/tmp/count
if ! [ -f $countfile ]
then
echo 0 》 $countfile
fi
do_count () {
exec 3《 $countfile
#對(duì)三號(hào)描述符加互斥鎖
flock -x 3
read -u 3 count
echo $((++count)) 》 $countfile
#解鎖
flock -u 3
#關(guān)閉描述符也會(huì)解鎖
exec 3》&-
}
for i in `seq 1 100`
do
do_count &
done
wait
cat $countfile
rm $countfile
?。踷orro@zorrozou-pc0 bash]$ 。/flock.sh
10012345678910111213141516171819202122232425262728293031323334
對(duì)臨界區(qū)代碼進(jìn)行加鎖處理之后,程序執(zhí)行結(jié)果正確了。仔細(xì)思考一下程序之后就會(huì)發(fā)現(xiàn),這里所謂的臨界區(qū)代碼由加鎖前的并行,變成了加鎖后的串行。flock的默認(rèn)行為是,如果文件之前沒(méi)被加鎖,則加鎖成功返回,如果已經(jīng)有人持有鎖,則加鎖行為會(huì)阻塞,直到成功加鎖。所以,我們也可以利用互斥鎖的這個(gè)特征,讓bash腳本不會(huì)重復(fù)執(zhí)行。
?。踷orro@zorrozou-pc0 bash]$ cat repeat.sh
#!/bin/bash
exec 3》 /tmp/.lock
if ! flock -xn 3
then
echo “already running!”
exit 1
fi
echo “running!”
sleep 30
echo “ending”
flock -u 3
exec 3》&-
rm /tmp/.lock
exit 01234567891011121314151617181920
-n參數(shù)可以讓flock命令以非阻塞方式探測(cè)一個(gè)文件是否已經(jīng)被加鎖,所以可以使用互斥鎖的特點(diǎn)保證腳本運(yùn)行的唯一性。腳本退出的時(shí)候鎖會(huì)被釋放,所以這里可以不用顯式的使用flock解鎖。flock除了-u參數(shù)指定文件描述符鎖文件以外,還可以作為執(zhí)行命令的前綴使用。這種方式非常適合直接在crond中方式所要執(zhí)行的腳本重復(fù)執(zhí)行。如:
*/1 * * * * /usr/bin/flock -xn /tmp/script.lock -c ‘/home/bash/script.sh’1
關(guān)于flock的其它參數(shù),可以man flock找到說(shuō)明。
受限bash
以受限模式執(zhí)行bash程序,有時(shí)候是很有必要的。這種模式可以保護(hù)我們的很多系統(tǒng)環(huán)境不受bash程序的誤操作影響。啟動(dòng)受限模式的bash的方法是使用-r參數(shù),或者也可以rbash的進(jìn)程名方式執(zhí)行bash。受限模式的bash和正常bash時(shí)間的差別是:
不能使用cd命令改變當(dāng)前工作目錄。
不能改變SHELL、PATH、ENV和BASH_ENV環(huán)境變量。
不能調(diào)用含有/的命令路徑。
不能使用。執(zhí)行帶有/字符的命令路徑。
不能使用hash命令的-p參數(shù)指定一個(gè)帶斜杠\的參數(shù)。
不能在shell環(huán)境啟動(dòng)的時(shí)候加載函數(shù)的定義。
不能檢查SHELLOPTS變量的內(nèi)容。
不能使用》, 》|, 《》, 》&, &》和 》》重定向操作符。
不能使用exec命令使用一個(gè)新程序替換當(dāng)前執(zhí)行的bash進(jìn)程。
enable內(nèi)建命令不能使用-f、-d參數(shù)。
不可以使用enable命令打開(kāi)或者關(guān)閉內(nèi)建命令。
command命令不可以使用-p參數(shù)。
不能使用set +r或者set +o restricted命令關(guān)閉受限模式。
測(cè)試一個(gè)簡(jiǎn)單的受限模式:
[zorro@zorrozou-pc0 bash]$ cat restricted.sh
#!/bin/bash
set -r
cd /tmp
?。踷orro@zorrozou-pc0 bash]$ 。/restricted.sh
。/restricted.sh: line 5: cd: restricted12345678
subshell
我們前面接觸過(guò)subshell的概念,我們之前說(shuō)的是,當(dāng)一個(gè)命令放在()中的時(shí)候,bash會(huì)打開(kāi)一個(gè)子進(jìn)程去執(zhí)行相關(guān)命令,這個(gè)子進(jìn)程實(shí)際上是另一個(gè)bash環(huán)境,叫做subshell。當(dāng)然包括放在()中執(zhí)行的命令,bash會(huì)在以下情況下打開(kāi)一個(gè)subshell執(zhí)行命令:
使用&作為命令結(jié)束提交了作業(yè)控制任務(wù)時(shí)。
使用|連接的命令會(huì)在subshell中打開(kāi)。
使用()封裝的命令。
使用coproc(bash 4.0版本之后支持)作為前綴執(zhí)行的命令。
要執(zhí)行的文件不存在或者文件存在但不具備可執(zhí)行權(quán)限的時(shí)候,這個(gè)執(zhí)行過(guò)程會(huì)打開(kāi)一個(gè)subshell執(zhí)行。
在subshell中,有些事情需要注意。subshell中的$$取到的仍然是父進(jìn)程bash的pid,如果想要取到subshell的pid,可以使用BASHPID變量:
?。踷orro@zorrozou-pc0 bash]$ echo $$ ;echo $BASHPID && (echo $$;echo $BASHPID)
5484
5484
5484
2458412345
可以使用BASH_SUBSHELL變量的值來(lái)檢查當(dāng)前環(huán)境是不是在subshell中,這個(gè)值在非subshell中是0;每進(jìn)入一層subshell就加1。
?。踷orro@zorrozou-pc0 bash]$ echo $BASH_SUBSHELL;(echo $BASH_SUBSHELL;(echo $BASH_SUBSHELL))
0
1
21234
在subshell中做的任何操作都不會(huì)影響父進(jìn)程的bash執(zhí)行環(huán)境。subshell除了PID和trap相關(guān)設(shè)置外,其他的環(huán)境都跟父進(jìn)程是一樣的。subshell的trap設(shè)置跟父進(jìn)程剛啟動(dòng)的時(shí)候還沒(méi)做trap設(shè)置之前一樣。
協(xié)進(jìn)程coprocess
在bash 4.0版本之后,為我們提供了一個(gè)coproc關(guān)鍵字可以支持協(xié)進(jìn)程。協(xié)進(jìn)程提供了一種可以上bash移步執(zhí)行另一個(gè)進(jìn)程的工作模式,實(shí)際上跟作業(yè)控制類似。嚴(yán)格來(lái)說(shuō),bash的協(xié)進(jìn)程就是使用作業(yè)控制作為實(shí)現(xiàn)手段來(lái)做的。它跟作業(yè)控制的區(qū)別僅僅在于,協(xié)進(jìn)程的標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出都在調(diào)用協(xié)進(jìn)程的bash中可以取到文件描述符,而作業(yè)控制進(jìn)程的標(biāo)準(zhǔn)輸入和輸出都是直接指向終端的。我們來(lái)看看使用協(xié)進(jìn)程的語(yǔ)法:
coproc [NAME] command [redirections]1
使用coproc作為前綴,后面加執(zhí)行的命令,可以將命令放到作業(yè)控制里執(zhí)行。并且在bash中可以通過(guò)一些方法查看到協(xié)進(jìn)程的pid和使用它的輸入和輸出。例子:
zorro@zorrozou-pc0 bash]$ cat coproc.sh
#!/bin/bash
#例一:簡(jiǎn)單命令使用
#簡(jiǎn)單命令使用不能通過(guò)NAME指定協(xié)進(jìn)程的名字,此時(shí)進(jìn)程的名字統(tǒng)一為:COPROC。
coproc tail -3 /etc/passwd
echo $COPROC_PID
exec 0《&${COPROC[0]}-
cat
#例二:復(fù)雜命令使用
#此時(shí)可以使用NAME參數(shù)指定協(xié)進(jìn)程名稱,并根據(jù)名稱產(chǎn)生的相關(guān)變量獲得協(xié)進(jìn)程pid和描述符。
coproc _cat { tail -3 /etc/passwd; }
echo $_cat_PID
exec 0《&${_cat[0]}-
cat
#例三:更復(fù)雜的命令以及輸入輸出使用
#協(xié)進(jìn)程的標(biāo)準(zhǔn)輸入描述符為:NAME[1],標(biāo)準(zhǔn)輸出描述符為:NAME[0]。
coproc print_username {
while read string
do
?。?“$string” = “END” ] && break
echo $string | awk -F: ‘{print $1}’
done
}
echo “aaa:bbb:ccc” 1》&${print_username[1]}
echo ok
read -u ${print_username[0]} username
echo $username
cat /etc/passwd 》&${print_username[1]}
echo END 》&${print_username[1]}
while read -u ${print_username[0]} username
do
echo $username
done123456789101112131415161718192021222324252627282930313233343536373839404142
執(zhí)行結(jié)果:
[zorro@zorrozou-pc0 bash]$ 。/coproc.sh
31953
jerry:x:1001:1001::/home/jerry:/bin/bash
systemd-coredump:x:994:994:systemd Core Dumper:/:/sbin/nologin
netdata:x:134:134::/var/cache/netdata:/bin/nologin
31955
jerry:x:1001:1001::/home/jerry:/bin/bash
systemd-coredump:x:994:994:systemd Core Dumper:/:/sbin/nologin
netdata:x:134:134::/var/cache/netdata:/bin/nologin
ok
aaa
root
bin
daemon
ftp
http
uuidd
dbus
nobody
systemd-journal-gateway
systemd-timesync
systemd-network
systemd-bus-proxy
systemd-resolve
systemd-journal-remote
systemd-journal-upload
polkitd
avahi
colord
rtkit
gdm
usbmux
git
gnome-initial-setup
zorro
nvidia-persistenced
ntp
jerry
systemd-coredump
netdata1234567891011121314151617181920212223242526272829303132333435363738394041
最后
本文主要介紹了一些bash編程的常用技巧,主要包括的知識(shí)點(diǎn)為:
/dev/和/proc目錄的使用。
函數(shù)和遞歸。
并發(fā)編程和flock。
受限bash。
subshell。
協(xié)進(jìn)程。
至此,我們的bash編程系列就算結(jié)束了。當(dāng)然,shell其實(shí)到現(xiàn)在才剛剛開(kāi)始。畢竟我們要真正實(shí)現(xiàn)有用的bash程序,還需要積累大量命令的使用。
評(píng)論