[转载] Python学习笔记——运维和Shell
參考鏈接: 在C / C++,Python,PHP和Java中交換兩個(gè)變量
目錄?
什么是運(yùn)維?
運(yùn)維第一工具-shell編程?
shell歷史?
執(zhí)行腳本?
基本語(yǔ)法?
Shell腳本語(yǔ)法?
條件測(cè)試:test [?
if/then/elif/else/fi?
case/esac?
for/do/done?
while/do/done?
break和continue?
位置參數(shù)和特殊變量?
shell輸入輸出?
函數(shù)?
Shell腳本的調(diào)試方法?
正則表達(dá)式?
grep?
find?
se?
awk?
Linux核心命令?
shell習(xí)題訓(xùn)練?
自動(dòng)化?
開(kāi)機(jī)自啟動(dòng)腳本?
?
什么是運(yùn)維?
? ?
??
術(shù)語(yǔ)名詞?
IDC--(Internet Data Center)互聯(lián)網(wǎng)數(shù)據(jù)中心,主要服務(wù)包括整機(jī)租用、服務(wù)器托管、機(jī)柜租用、機(jī)房租用、專(zhuān)線接入和網(wǎng)絡(luò)管理服務(wù)等。廣義上的IDC業(yè)務(wù),實(shí)際上就是數(shù)據(jù)中心所提供的一切服務(wù)。客戶(hù)租用數(shù)據(jù)中心的服務(wù)器和帶寬,并利用數(shù)據(jù)中心的技術(shù)力量,來(lái)實(shí)現(xiàn)自己對(duì)軟、硬件的要求,搭建自己的互聯(lián)網(wǎng)平臺(tái),享用數(shù)據(jù)中心所提供的一系列服務(wù)。ISP--(Internet Service Provider)互聯(lián)網(wǎng)服務(wù)提供商,即向廣大用戶(hù)綜合提供互聯(lián)網(wǎng)接入業(yè)務(wù)、信息業(yè)務(wù)、和增值業(yè)務(wù)的電信運(yùn)營(yíng)商。ICP--(Internet Content Provider)互聯(lián)網(wǎng)內(nèi)容提供商,向廣大用戶(hù)綜合提供互聯(lián)網(wǎng)信息業(yè)務(wù)和增值業(yè)務(wù)的電信運(yùn)營(yíng)商。 根據(jù)中華人民共和國(guó)國(guó)務(wù)院令第292號(hào)《互聯(lián)網(wǎng)信息服務(wù)管理辦法》規(guī)定,國(guó)家對(duì)提供互聯(lián)網(wǎng)信息服務(wù)的ICP實(shí)行許可證制度。從而,ICP證成為網(wǎng)站經(jīng)營(yíng)的許可證,經(jīng)營(yíng)性網(wǎng)站必須辦理ICP證,否則就屬于非法經(jīng)營(yíng)。因此,辦理ICP證是企業(yè)網(wǎng)站合法經(jīng)營(yíng)的需要.CDN--(Content Delivery Network)內(nèi)容分發(fā)網(wǎng)絡(luò),依靠部署在各地的邊緣服務(wù)器,通過(guò)中心平臺(tái)的負(fù)載均衡、內(nèi)容分發(fā)、調(diào)度等功能模塊,使用戶(hù)就近獲取所需內(nèi)容,降低網(wǎng)絡(luò)擁塞,提高用戶(hù)訪問(wèn)響應(yīng)速度和命中率。CDN的關(guān)鍵技術(shù)主要有內(nèi)容存儲(chǔ)和分發(fā)技術(shù)。 CDN的基本原理是廣泛采用各種緩存服務(wù)器,將這些緩存服務(wù)器分布到用戶(hù)訪問(wèn)相對(duì)集中的地區(qū)或網(wǎng)絡(luò)中,在用戶(hù)訪問(wèn)網(wǎng)站時(shí),利用全局負(fù)載技術(shù)將用戶(hù)的訪問(wèn)指向距離最近的工作正常的緩存服務(wù)器上,由緩存服務(wù)器直接響應(yīng)用戶(hù)請(qǐng)求。LVS--(Linux Virtual Server)的簡(jiǎn)寫(xiě),意即Linux虛擬服務(wù)器,是一個(gè)虛擬的服務(wù)器集群系統(tǒng)。LVS集群采用IP負(fù)載均衡技術(shù)和基于內(nèi)容請(qǐng)求分發(fā)技術(shù)。調(diào)度器具有很好的吞吐率,將請(qǐng)求均衡地轉(zhuǎn)移到不同的服務(wù)器上執(zhí)行,且調(diào)度器自動(dòng)屏蔽掉服務(wù)器的故障,從而將一組服務(wù)器構(gòu)成一個(gè)高性能的、高可用的虛擬服務(wù)器。整個(gè)服務(wù)器集群的結(jié)構(gòu)對(duì)客戶(hù)是透明的,而且無(wú)需修改客戶(hù)端和服務(wù)器端的程序。為此,在設(shè)計(jì)時(shí)需要考慮系統(tǒng)的透明性、可伸縮性、高可用性和易管理性。 CGI--(Common Gateway Interface)通用網(wǎng)關(guān)接口。CGI規(guī)范允許Web服務(wù)器執(zhí)行外部程序,并將它們的輸出發(fā)送給Web瀏覽器,CGI將Web的一組簡(jiǎn)單的靜態(tài)超媒體文檔變成一個(gè)完整的新的交互式媒體? GSLB--(Global Server Load Balance,全局負(fù)載均衡)作為 CDN 系統(tǒng)架構(gòu)中最核心的部分,負(fù)責(zé)流量調(diào)度.基于DNS的GSLB 絕大部分使用負(fù)載均衡技術(shù)的應(yīng)用都通過(guò)域名來(lái)訪問(wèn)目的主機(jī),在用戶(hù)發(fā)出任何應(yīng)用連接請(qǐng)求時(shí),首先必須通過(guò)DNS請(qǐng)求獲得服務(wù)器的IP地址,基于DNS的GSLB正是在返回DNS解析結(jié)果的過(guò)程中進(jìn)行智能決策,給用戶(hù)返回一個(gè)最佳的服務(wù)IP。用戶(hù)應(yīng)用流程與沒(méi)有GSLB時(shí)未發(fā)生任何變化。這也是市場(chǎng)上主流的GSLB技術(shù)。? BOSS--(Business & Operation Support System,BOSS)是業(yè)務(wù)運(yùn)營(yíng)支撐系統(tǒng)。通常所說(shuō)的BOSS分為四個(gè)部分:計(jì)費(fèi)及結(jié)算系統(tǒng)、營(yíng)業(yè)與賬務(wù)系統(tǒng)、客戶(hù)服務(wù)系統(tǒng)和決策支持系統(tǒng)。BOSS從業(yè)務(wù)層面來(lái)看就是一個(gè)框架,來(lái)承載業(yè)務(wù)系統(tǒng)、CRM系統(tǒng)、計(jì)費(fèi)系統(tǒng)。實(shí)現(xiàn)統(tǒng)一框架中的縱向、橫向管理。該系統(tǒng)最早由電信部門(mén)的計(jì)費(fèi)系統(tǒng)發(fā)展演變而來(lái),基本功能包括客戶(hù)資料管理、產(chǎn)品管理、用戶(hù)訂購(gòu)管理、計(jì)費(fèi)、出帳、結(jié)算等,負(fù)責(zé)登記客戶(hù)資料、管理用戶(hù)訂購(gòu)服務(wù)的提供、實(shí)時(shí)的根據(jù)不同產(chǎn)品、套餐的資費(fèi)標(biāo)準(zhǔn)計(jì)算業(yè)務(wù)(手機(jī)、固定電話(huà)用戶(hù)通話(huà)時(shí)、點(diǎn)播收視、寬帶流量與時(shí)間等)的消費(fèi)金額,準(zhǔn)實(shí)時(shí)及定期計(jì)算用戶(hù)帳單,實(shí)時(shí)或定期結(jié)算用戶(hù)各種消費(fèi)費(fèi)用。?
管理?
配置管理事件管理問(wèn)題管理成本管理容量管理資源管理需求管理
規(guī)劃?
架構(gòu)規(guī)劃IDC規(guī)劃服務(wù)器規(guī)劃ISP規(guī)劃預(yù)算規(guī)劃
優(yōu)化?
速度優(yōu)化成本優(yōu)化ISP優(yōu)化CDN優(yōu)化告警優(yōu)化故障預(yù)案故障演習(xí)
安全?
漏洞掃描域名劫持掃描掛馬掃描CGI掃描網(wǎng)頁(yè)篡改掃描
告警?
告警模型告警故障告警統(tǒng)計(jì)告警關(guān)聯(lián)撥測(cè) 定時(shí)curl一下某個(gè)url,有問(wèn)題就告警.
日志告警:5分鐘Error大于xxx次告警。
指標(biāo)告警:cpu使用率大于xxx告警。
?
告警對(duì)象可以分為兩種:?
業(yè)務(wù)規(guī)則監(jiān)控系統(tǒng)可靠性監(jiān)控
對(duì)于業(yè)務(wù)規(guī)則監(jiān)控可以舉一個(gè)游戲的例子。比如游戲角色在一定裝備的情況下,單次打擊的傷害輸出應(yīng)該是有一個(gè)上限,如果超過(guò)了就說(shuō)明有作弊的情況。又比如斗地主游戲里一個(gè)人的連勝場(chǎng)次是有一定上限的,每天的勝率是有一定上限,如果超出平均值太多就可能是作弊。業(yè)務(wù)規(guī)則監(jiān)控的不是硬件,也不是軟件是否工作正常。而是軟件是否按照業(yè)務(wù)規(guī)則實(shí)現(xiàn)的,是否有漏洞。也可以理解為對(duì)“正確性”的監(jiān)控。?
系統(tǒng)可靠性監(jiān)控是最常見(jiàn)的監(jiān)控形式,比如發(fā)現(xiàn)是不是服務(wù)器掛掉了,服務(wù)是不是過(guò)載了等等。對(duì)于大部分后臺(tái)服務(wù),系統(tǒng)可以抽象建模成這個(gè)樣子:?
監(jiān)控?
URL監(jiān)控LVS監(jiān)控IDC監(jiān)控?cái)?shù)據(jù)庫(kù)監(jiān)控模塊監(jiān)控站點(diǎn)監(jiān)控響應(yīng)監(jiān)控
系統(tǒng)/平臺(tái)?
CDN平臺(tái)靜態(tài)應(yīng)用平臺(tái)動(dòng)態(tài)應(yīng)用平臺(tái)點(diǎn)擊流系統(tǒng)數(shù)據(jù)庫(kù)平臺(tái)下載平臺(tái)網(wǎng)絡(luò)健康系統(tǒng)經(jīng)營(yíng)分析系統(tǒng)存儲(chǔ)平臺(tái)流媒體平臺(tái)質(zhì)量監(jiān)測(cè)系統(tǒng)GSLB管理系統(tǒng)BOSS系統(tǒng)立體監(jiān)控系統(tǒng)自動(dòng)發(fā)布系統(tǒng)站點(diǎn)分析系統(tǒng)統(tǒng)一告警系統(tǒng)運(yùn)維工具系統(tǒng)
規(guī)范?
項(xiàng)目立項(xiàng)規(guī)范運(yùn)營(yíng)故障分級(jí)和處罰規(guī)范重大運(yùn)營(yíng)故障處理流程環(huán)境一致性規(guī)范運(yùn)營(yíng)資源申請(qǐng)流程IDC變更流程預(yù)算管理規(guī)范
linux發(fā)行版?
RedHat: Fedora, CentOS, MandrivaSuSE: SLES, OpenSuSEDebian: UbuntuGentoo:BackTrace/kali linux (黑客)
運(yùn)維第一工具-shell編程?
shell歷史?
Shell的作用是解釋執(zhí)行用戶(hù)的命令,用戶(hù)輸入一條命令,Shell就解釋執(zhí)行一條,這種方式稱(chēng)為交互式(Interactive),Shell還有一種執(zhí)行命令的方式稱(chēng)為批處理(Batch),用戶(hù)事先寫(xiě)一個(gè)Shell腳本(Script),其中有很多條命令,讓Shell一次把這些命令執(zhí)行完,而不必一條一條地敲命令。Shell腳本和編程語(yǔ)言很相似,也有變量和流程控制語(yǔ)句,但Shell腳本是解釋執(zhí)行的,不需要編譯,Shell程序從腳本中一行一行讀取并執(zhí)行這些命令,相當(dāng)于一個(gè)用戶(hù)把腳本中的命令一行一行敲到Shell提示符下執(zhí)行。?
由于歷史原因,UNIX系統(tǒng)上有很多種Shell:?
1.sh(Bourne Shell):由Steve Bourne開(kāi)發(fā),各種UNIX系統(tǒng)都配有sh。?
2.csh(C Shell):由Bill Joy開(kāi)發(fā),隨BSD UNIX發(fā)布,它的流程控制語(yǔ)句很像C語(yǔ)言,支持很多Bourne Shell所不支持的功能:作業(yè)控制,命令歷史,命令行編輯。?
3.ksh(Korn Shell):由David Korn開(kāi)發(fā),向后兼容sh的功能,并且添加了csh引入的新功能,是目前很多UNIX系統(tǒng)標(biāo)準(zhǔn)配置的Shell,在這些系統(tǒng)上/bin/sh往往是指向/bin/ksh的符號(hào)鏈接。?
4.tcsh(TENEX C Shell):是csh的增強(qiáng)版本,引入了命令補(bǔ)全等功能,在FreeBSD、Mac OS X等系統(tǒng)上替代了csh。?
5.bash(Bourne Again Shell):由GNU開(kāi)發(fā)的Shell,主要目標(biāo)是與POSIX標(biāo)準(zhǔn)保持一致,同時(shí)兼顧對(duì)sh的兼容,bash從csh和ksh借鑒了很多功能,是各種Linux發(fā)行版標(biāo)準(zhǔn)配置的Shell,在Linux系統(tǒng)上/bin/sh往往是指向/bin/bash的符號(hào)鏈接。雖然如此,bash和sh還是有很多不同的,一方面,bash擴(kuò)展了一些命令和參數(shù),另一方面,bash并不完全和sh兼容,有些行為并不一致,所以bash需要模擬sh的行為:當(dāng)我們通過(guò)sh這個(gè)程序名啟動(dòng)bash時(shí),bash可以假裝自己是sh,不認(rèn)擴(kuò)展的命令,并且行為與sh保持一致。?
6.zsh 的命令補(bǔ)全功能非常強(qiáng)大,可以補(bǔ)齊路徑,補(bǔ)齊命令,補(bǔ)齊參數(shù)等。?
vim /etc/passwd
其中最后一列顯示了用戶(hù)對(duì)應(yīng)的shell類(lèi)型
?
root:x:0:0:root:/root:/bin/bash
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false
itcast:x:1000:1000:itcast,,,:/home/itcast:/bin/bash
ftp:x:115:125:ftp daemon,,,:/srv/ftp:/bin/false
?
用戶(hù)在命令行輸入命令后,一般情況下Shell會(huì)fork并exec該命令,但是Shell的內(nèi)建命令例外,執(zhí)行內(nèi)建命令相當(dāng)于調(diào)用Shell進(jìn)程中的一個(gè)函數(shù),并不創(chuàng)建新的進(jìn)程。以前學(xué)過(guò)的cd、alias、umask、exit等命令即是內(nèi)建命令,凡是用which命令查不到程序文件所在位置的命令都是內(nèi)建命令,內(nèi)建命令沒(méi)有單獨(dú)的man手冊(cè),要在man手冊(cè)中查看內(nèi)建命令,應(yīng)該?
$ man bash-builtins
?
如export、shift、if、eval、[、for、while等等。內(nèi)建命令雖然不創(chuàng)建新的進(jìn)程,但也會(huì)有Exit Status,通常也用0表示成功非零表示失敗,雖然內(nèi)建命令不創(chuàng)建新的進(jìn)程,但執(zhí)行結(jié)束后也會(huì)有一個(gè)狀態(tài)碼,也可以用特殊變量$?讀出。?
執(zhí)行腳本?
編寫(xiě)一個(gè)簡(jiǎn)單的腳本test.sh:?
#! /bin/sh
cd ..
ls
?
Shell腳本中用#表示注釋,相當(dāng)于C語(yǔ)言的//注釋。但如果#位于第一行開(kāi)頭,并且是#!(稱(chēng)為Shebang)則例外,它表示該腳本使用后面指定的解釋器/bin/sh解釋執(zhí)行。如果把這個(gè)腳本文件加上可執(zhí)行權(quán)限然后執(zhí)行:?
chmod a+x test.sh
./test.sh
?
Shell會(huì)fork一個(gè)子進(jìn)程并調(diào)用exec執(zhí)行./test.sh這個(gè)程序,exec系統(tǒng)調(diào)用應(yīng)該把子進(jìn)程的代碼段替換成./test.sh程序的代碼段,并從它的_start開(kāi)始執(zhí)行。然而test.sh是個(gè)文本文件,根本沒(méi)有代碼段和_start函數(shù),怎么辦呢?其實(shí)exec還有另外一種機(jī)制,如果要執(zhí)行的是一個(gè)文本文件,并且第一行用Shebang指定了解釋器,則用解釋器程序的代碼段替換當(dāng)前進(jìn)程,并且從解釋器的_start開(kāi)始執(zhí)行,而這個(gè)文本文件被當(dāng)作命令行參數(shù)傳給解釋器。因此,執(zhí)行上述腳本相當(dāng)于執(zhí)行程序?
$ /bin/sh ./test.sh
?
以這種方式執(zhí)行不需要test.sh文件具有可執(zhí)行權(quán)限。?
如果將命令行下輸入的命令用()括號(hào)括起來(lái),那么也會(huì)fork出一個(gè)子Shell執(zhí)行小括號(hào)中的命令,一行中可以輸入由分號(hào);隔開(kāi)的多個(gè)命令,比如:?
$ (cd ..;ls -l)
?
和上面兩種方法執(zhí)行Shell腳本的效果是相同的,cd ..命令改變的是子Shell的PWD,而不會(huì)影響到交互式Shell。然而命令?
$ cd ..;ls -l
?
則有不同的效果,cd ..命令是直接在交互式Shell下執(zhí)行的,改變交互式Shell的PWD,然而這種方式相當(dāng)于這樣執(zhí)行Shell腳本:?
$ source ./test.sh
?
或者?
$ . ./test.sh
?
source或者.命令是Shell的內(nèi)建命令,這種方式也不會(huì)創(chuàng)建子Shell,而是直接在交互式Shell下逐行執(zhí)行腳本中的命令。?
基本語(yǔ)法?
變量?
按照慣例,Shell變量由全大寫(xiě)字母加下劃線組成,有兩種類(lèi)型的Shell變量:?
1.環(huán)境變量?
環(huán)境變量可以從父進(jìn)程傳給子進(jìn)程,因此Shell進(jìn)程的環(huán)境變量可以從當(dāng)前Shell進(jìn)程傳給fork出來(lái)的子進(jìn)程。用printenv命令可以顯示當(dāng)前Shell進(jìn)程的環(huán)境變量。?
2.本地變量?
只存在于當(dāng)前Shell進(jìn)程,用set命令可以顯示當(dāng)前Shell進(jìn)程中定義的所有變量(包括本地變量和環(huán)境變量)和函數(shù)。?
環(huán)境變量是任何進(jìn)程都有的概念,而本地變量是Shell特有的概念。在Shell中,環(huán)境變量和本地變量的定義和用法相似。在Shell中定義或賦值一個(gè)變量:?
itcast$ VARNAME=value
?
注意等號(hào)兩邊都不能有空格,否則會(huì)被Shell解釋成命令和命令行參數(shù)。?
一個(gè)變量定義后僅存在于當(dāng)前Shell進(jìn)程,它是本地變量,用export命令可以把本地變量導(dǎo)出為環(huán)境變量,定義和導(dǎo)出環(huán)境變量通常可以一步完成:?
itcast$ export VARNAME=value
?
也可以分兩步完成:?
itcast$ VARNAME=value
itcast$ export VARNAME
?
用unset命令可以刪除已定義的環(huán)境變量或本地變量。?
itcast$ unset VARNAME
?
如果一個(gè)變量叫做VARNAME,用${VARNAME}可以表示它的值,在不引起歧義的情況下也可以用$VARNAME表示它的值。通過(guò)以下例子比較這兩種表示法的不同:?
itcast$ echo $SHELL
?
注意,在定義變量時(shí)不用$,取變量值時(shí)要用$。和C語(yǔ)言不同的是,Shell變量不需要明確定義類(lèi)型,事實(shí)上Shell變量的值都是字符串,比如我們定義VAR=45,其實(shí)VAR的值是字符串45而非整數(shù)。Shell變量不需要先定義后使用,如果對(duì)一個(gè)沒(méi)有定義的變量取值,則值為空字符串。?
文件名代換(Globbing):* ? []?
這些用于匹配的字符稱(chēng)為通配符(Wildcard),具體如下:?
通配符
?
*? ?匹配0個(gè)或多個(gè)任意字符
?? ?匹配一個(gè)任意字符
[若干字符]? 匹配方括號(hào)中任意一個(gè)字符的一次出現(xiàn)
?
$ ls /dev/ttyS*
$ ls ch0?.doc
$ ls ch0[0-2].doc
$ ls ch[012]? ?[0-9].doc
?
注意,Globbing所匹配的文件名是由Shell展開(kāi)的,也就是說(shuō)在參數(shù)還沒(méi)傳給程序之前已經(jīng)展開(kāi)了,比如上述ls ch0[012].doc命令,如果當(dāng)前目錄下有ch00.doc和ch02.doc,則傳給ls命令的參數(shù)實(shí)際上是這兩個(gè)文件名,而不是一個(gè)匹配字符串。?
命令代換:`或 $()?
由'`'反引號(hào)括起來(lái)的也是一條命令,Shell先執(zhí)行該命令,然后將輸出結(jié)果立刻代換到當(dāng)前命令行中。例如定義一個(gè)變量存放date命令的輸出:?
itcast$ DATE=`date`
itcast$ echo $DATE
?
命令代換也可以用$()表示:?
itcast$ DATE=$(date)
?
算術(shù)代換:$(())?
用于算術(shù)計(jì)算,$(())中的Shell變量取值將轉(zhuǎn)換成整數(shù),同樣含義的$[]等價(jià)例如:?
itcast$ VAR=45
itcast$ echo $(($VAR+3))
$(())中只能用+-*/和()運(yùn)算符,并且只能做整數(shù)運(yùn)算。
?
$[base#n],其中base表示進(jìn)制,n按照base進(jìn)制解釋,后面再有運(yùn)算數(shù),按十進(jìn)制解釋。
?
echo $[2#10+11]
echo $[8#10+11]
echo $[10#10+11]
?
轉(zhuǎn)義字符\?
和C語(yǔ)言類(lèi)似,\在Shell中被用作轉(zhuǎn)義字符,用于去除緊跟其后的單個(gè)字符的特殊意義(回車(chē)除外),換句話(huà)說(shuō),緊跟其后的字符取字面值。例如:?
itcast$ echo $SHELL
/bin/bash
itcast$ echo \$SHELL
$SHELL
itcast$ echo \\
\
?
比如創(chuàng)建一個(gè)文件名為“$ $”的文件可以這樣:?
itcast$ touch \$\ \$
?
還有一個(gè)字符雖然不具有特殊含義,但是要用它做文件名也很麻煩,就是-號(hào)。如果要?jiǎng)?chuàng)建一個(gè)文件名以-號(hào)開(kāi)頭的文件,這樣是不行的:?
itcast$ touch -hello
touch: invalid option -- h
Try `touch --help' for more information.
?
即使加上\轉(zhuǎn)義也還是報(bào)錯(cuò):
?
itcast$ touch \-hello
touch: invalid option -- h
Try `touch --help' for more information.
?
因?yàn)楦鞣NUNIX命令都把-號(hào)開(kāi)頭的命令行參數(shù)當(dāng)作命令的選項(xiàng),而不會(huì)當(dāng)作文件名。如果非要處理以-號(hào)開(kāi)頭的文件名,可以有兩種辦法:?
itcast$ touch ./-hello
?
或者?
itcast$ touch -- -hello
?
\還有一種用法,在\后敲回車(chē)表示續(xù)行,Shell并不會(huì)立刻執(zhí)行命令,而是把光標(biāo)移到下一行,給出一個(gè)續(xù)行提示符>,等待用戶(hù)繼續(xù)輸入,最后把所有的續(xù)行接到一起當(dāng)作一個(gè)命令執(zhí)行。例如:?
itcast$ ls \
> -l
(ls -l命令的輸出)
?
單引號(hào)?
和C語(yǔ)言不一樣,Shell腳本中的單引號(hào)和雙引號(hào)一樣都是字符串的界定符(雙引號(hào)下一節(jié)介紹),而不是字符的界定符。單引號(hào)用于保持引號(hào)內(nèi)所有字符的字面值,即使引號(hào)內(nèi)的\和回車(chē)也不例外,但是字符串中不能出現(xiàn)單引號(hào)。如果引號(hào)沒(méi)有配對(duì)就輸入回車(chē),Shell會(huì)給出續(xù)行提示符,要求用戶(hù)把引號(hào)配上對(duì)。例如:?
itcast$ echo '$SHELL'
$SHELL
itcast$ echo 'ABC\(回車(chē))
> DE'(再按一次回車(chē)結(jié)束命令)
ABC\
DE
?
雙引號(hào)?
被雙引號(hào)用括住的內(nèi)容,將被視為單一字串。它防止通配符擴(kuò)展,但允許變量擴(kuò)展。這點(diǎn)與單引號(hào)的處理方式不同?
itcast$ DATE=$(date)
itcast$ echo "$DATE"
itcast$ echo '$DATE'
?
Shell腳本語(yǔ)法?
條件測(cè)試:test [?
命令test或[可以測(cè)試一個(gè)條件是否成立,如果測(cè)試結(jié)果為真,則該命令的Exit Status為0,如果測(cè)試結(jié)果為假,則命令的Exit Status為1(注意與C語(yǔ)言的邏輯表示正好相反)。例如測(cè)試兩個(gè)數(shù)的大小關(guān)系:?
itcast@ubuntu:~$ var=2
itcast@ubuntu:~$ test $var -gt 1
itcast@ubuntu:~$ echo $?
0
itcast@ubuntu:~$ test $var -gt 3
itcast@ubuntu:~$ echo $?
1
itcast@ubuntu:~$ [ $var -gt 3 ]
itcast@ubuntu:~$ echo $?
1
itcast@ubuntu:~$
?
雖然看起來(lái)很奇怪,但左方括號(hào)[確實(shí)是一個(gè)命令的名字,傳給命令的各參數(shù)之間應(yīng)該用空格隔開(kāi),比如,$VAR、-gt、3、]是[命令的四個(gè)參數(shù),它們之間必須用空格隔開(kāi)。命令test或[的參數(shù)形式是相同的,只不過(guò)test命令不需要]參數(shù)。以[命令為例,常見(jiàn)的測(cè)試命令如下表所示:?
[ -d DIR ]? ? ? ? ? ? ? 如果DIR存在并且是一個(gè)目錄則為真
[ -f FILE ]? ? ? ? ? ? ?如果FILE存在且是一個(gè)普通文件則為真
[ -z STRING ]? ? ? ? ? ?如果STRING的長(zhǎng)度為零則為真
[ -n STRING ]? ? ? ? ? ?如果STRING的長(zhǎng)度非零則為真
[ STRING1 = STRING2 ]? ?如果兩個(gè)字符串相同則為真
[ STRING1 != STRING2 ]? 如果字符串不相同則為真
[ ARG1 OP ARG2 ]? ? ? ? ARG1和ARG2應(yīng)該是整數(shù)或者取值為整數(shù)的變量,OP是-eq(等于)-ne(不等于)-lt(小于)-le(小于等于)-gt(大于)-ge(大于等于)之中的一個(gè)
?
和C語(yǔ)言類(lèi)似,測(cè)試條件之間還可以做與、或、非邏輯運(yùn)算:?
帶與、或、非的測(cè)試命令
?
[ ! EXPR ]? ? ? ? ? EXPR可以是上表中的任意一種測(cè)試條件,!表示邏輯反
[ EXPR1 -a EXPR2 ]? EXPR1和EXPR2可以是上表中的任意一種測(cè)試條件,-a表示邏輯與
[ EXPR1 -o EXPR2 ]? EXPR1和EXPR2可以是上表中的任意一種測(cè)試條件,-o表示邏輯或
?
例如:?
$ VAR=abc
$ [ -d Desktop -a $VAR = 'abc' ]
$ echo $?
0
?
注意,如果上例中的$VAR變量事先沒(méi)有定義,則被Shell展開(kāi)為空字符串,會(huì)造成測(cè)試條件的語(yǔ)法錯(cuò)誤(展開(kāi)為[ -d Desktop -a = 'abc' ]),作為一種好的Shell編程習(xí)慣,應(yīng)該總是把變量取值放在雙引號(hào)之中(展開(kāi)為[ -d Desktop -a "" = 'abc' ]):?
$ unset VAR
$ [ -d Desktop -a $VAR = 'abc' ]
bash: [: too many arguments
$ [ -d Desktop -a "$VAR" = 'abc' ]
$ echo $?
1
?
if/then/elif/else/fi?
和C語(yǔ)言類(lèi)似,在Shell中用if、then、elif、else、fi這幾條命令實(shí)現(xiàn)分支控制。這種流程控制語(yǔ)句本質(zhì)上也是由若干條Shell命令組成的,例如先前講過(guò)的?
if [ -f ~/.bashrc ]; then
? ? . ~/.bashrc
fi
?
其實(shí)是三條命令,if [ -f ~/.bashrc ]是第一條,then . ~/.bashrc是第二條,fi是第三條。如果兩條命令寫(xiě)在同一行則需要用;號(hào)隔開(kāi),一行只寫(xiě)一條命令就不需要寫(xiě);號(hào)了,另外,then后面有換行,但這條命令沒(méi)寫(xiě)完,Shell會(huì)自動(dòng)續(xù)行,把下一行接在then后面當(dāng)作一條命令處理。和[命令一樣,要注意命令和各參數(shù)之間必須用空格隔開(kāi)。if命令的參數(shù)組成一條子命令,如果該子命令的Exit Status為0(表示真),則執(zhí)行then后面的子命令,如果Exit Status非0(表示假),則執(zhí)行elif、else或者fi后面的子命令。if后面的子命令通常是測(cè)試命令,但也可以是其它命令。Shell腳本沒(méi)有{}括號(hào),所以用fi表示if語(yǔ)句塊的結(jié)束。見(jiàn)下例:?
#! /bin/sh
?
if [ -f /bin/bash ]
then echo "/bin/bash is a file"
else echo "/bin/bash is NOT a file"
fi
if :; then echo "always true"; fi
?
:是一個(gè)特殊的命令,稱(chēng)為空命令,該命令不做任何事,但Exit Status總是真。此外,也可以執(zhí)行/bin/true或/bin/false得到真或假的Exit Status。再看一個(gè)例子:?
? ? #! /bin/sh
?
? ? echo "Is it morning? Please answer yes or no."
? ? read YES_OR_NO
? ? if [ "$YES_OR_NO" = "yes" ]; then
? ? ? echo "Good morning!"
? ? elif [ "$YES_OR_NO" = "no" ]; then
? ? ? echo "Good afternoon!"
? ? else
? ? ? echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
? ? ? exit 1
? ? fi
? ? exit 0
?
上例中的read命令的作用是等待用戶(hù)輸入一行字符串,將該字符串存到一個(gè)Shell變量中。?
此外,Shell還提供了&&和||語(yǔ)法,和C語(yǔ)言類(lèi)似,具有Short-circuit特性,很多Shell腳本喜歡寫(xiě)成這樣:?
test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)
?
&&相當(dāng)于“if...then...”,而||相當(dāng)于“if not...then...”。&&和||用于連接兩個(gè)命令,而上面講的-a和-o僅用于在測(cè)試表達(dá)式中連接兩個(gè)測(cè)試條件,要注意它們的區(qū)別,例如,?
test "$VAR" -gt 1 -a "$VAR" -lt 3
?
和以下寫(xiě)法是等價(jià)的?
test "$VAR" -gt 1 && test "$VAR" -lt 3
?
case/esac?
case命令可類(lèi)比C語(yǔ)言的switch/case語(yǔ)句,esac表示case語(yǔ)句塊的結(jié)束。C語(yǔ)言的case只能匹配整型或字符型常量表達(dá)式,而Shell腳本的case可以匹配字符串和Wildcard,每個(gè)匹配分支可以有若干條命令,末尾必須以;;結(jié)束,執(zhí)行時(shí)找到第一個(gè)匹配的分支并執(zhí)行相應(yīng)的命令,然后直接跳到esac之后,不需要像C語(yǔ)言一樣用break跳出。?
? ? #! /bin/sh
?
? ? echo "Is it morning? Please answer yes or no."
? ? read YES_OR_NO
? ? case "$YES_OR_NO" in
? ? yes|y|Yes|YES)
? ? ? echo "Good Morning!";;
? ? [nN]*)
? ? ? echo "Good Afternoon!";;
? ? *)
? ? ? echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
? ? ? exit 1;;
? ? esac
? ? exit 0
?
使用case語(yǔ)句的例子可以在系統(tǒng)服務(wù)的腳本目錄/etc/init.d中找到。這個(gè)目錄下的腳本大多具有這種形式(以/etc/init.d/nfs-kernel-server為例):?
? ? case "$1" in
? ? ? ? start)
? ? ? ? ? ? ...
? ? ? ? ;;
? ? ? ? stop)
? ? ? ? ? ? ...
? ? ? ? ;;
? ? ? ? reload | force-reload)
? ? ? ? ? ? ...
? ? ? ? ;;
? ? ? ? restart)
? ? ? ? ...
? ? ? ? *)
? ? ? ? ? ? log_success_msg "Usage: nfs-kernel-server {start|stop|status|reload|force-reload|restart}"
? ? ? ? ? ? exit 1
? ? ? ? ;;
? ? esac
?
啟動(dòng)nfs-kernel-server服務(wù)的命令是?
$ sudo /etc/init.d/nfs-kernel-server start
?
$1是一個(gè)特殊變量,在執(zhí)行腳本時(shí)自動(dòng)取值為第一個(gè)命令行參數(shù),也就是start,所以進(jìn)入start)分支執(zhí)行相關(guān)的命令。同理,命令行參數(shù)指定為stop、reload或restart可以進(jìn)入其它分支執(zhí)行停止服務(wù)、重新加載配置文件或重新啟動(dòng)服務(wù)的相關(guān)命令。?
for/do/done?
Shell腳本的for循環(huán)結(jié)構(gòu)和C語(yǔ)言很不一樣,它類(lèi)似于某些編程語(yǔ)言的foreach循環(huán)。例如:?
? ? #! /bin/sh
?
? ? for FRUIT in apple banana pear; do
? ? ? echo "I like $FRUIT"
? ? done
?
FRUIT是一個(gè)循環(huán)變量,第一次循環(huán)$FRUIT的取值是apple,第二次取值是banana,第三次取值是pear。再比如,要將當(dāng)前目錄下的chap0、chap1、chap2等文件名改為chap0~、chap1~、chap2~等(按慣例,末尾有~字符的文件名表示臨時(shí)文件),這個(gè)命令可以這樣寫(xiě):
?
$ for FILENAME in chap?; do mv $FILENAME $FILENAME~; done
?
也可以這樣寫(xiě):?
$ for FILENAME in `ls chap?`; do mv $FILENAME $FILENAME~; done
?
while/do/done?
while的用法和C語(yǔ)言類(lèi)似。比如一個(gè)驗(yàn)證密碼的腳本:?
? ? #! /bin/sh
?
? ? echo "Enter password:"
? ? read TRY
? ? while [ "$TRY" != "secret" ]; do
? ? ? echo "Sorry, try again"
? ? ? read TRY
? ? done
?
下面的例子通過(guò)算術(shù)運(yùn)算控制循環(huán)的次數(shù):?
? ? #! /bin/sh
?
? ? COUNTER=1
? ? while [ "$COUNTER" -lt 10 ]; do
? ? ? echo "Here we go again"
? ? ? COUNTER=$(($COUNTER+1))
? ? done
?
Shell還有until循環(huán),類(lèi)似C語(yǔ)言的do...while循環(huán)。本章從略。?
break和continue?
break[n]可以指定跳出幾層循環(huán),continue跳過(guò)本次循環(huán)步,沒(méi)跳出整個(gè)循環(huán)。?
break跳出,continue跳過(guò)。?
習(xí)題?
1、把上面驗(yàn)證密碼的程序修改一下,如果用戶(hù)輸錯(cuò)五次密碼就報(bào)錯(cuò)退出。?
位置參數(shù)和特殊變量?
有很多特殊變量是被Shell自動(dòng)賦值的,我們已經(jīng)遇到了$?和$1,現(xiàn)在總結(jié)一下:?
常用的位置參數(shù)和特殊變量?
$0? 相當(dāng)于C語(yǔ)言main函數(shù)的argv[0]
$1、$2...? ? 這些稱(chēng)為位置參數(shù)(Positional Parameter),相當(dāng)于C語(yǔ)言main函數(shù)的argv[1]、argv[2]...
$#? 相當(dāng)于C語(yǔ)言main函數(shù)的argc - 1,注意這里的#后面不表示注釋
$@? 表示參數(shù)列表"$1" "$2" ...,例如可以用在for循環(huán)中的in后面。
$*? 表示參數(shù)列表"$1" "$2" ...,同上
$?? 上一條命令的Exit Status
$$? 當(dāng)前進(jìn)程號(hào)
?
位置參數(shù)可以用shift命令左移。比如shift 3表示原來(lái)的$4現(xiàn)在變成$1,原來(lái)的$5現(xiàn)在變成$2等等,原來(lái)的$1、$2、$3丟棄,$0不移動(dòng)。不帶參數(shù)的shift命令相當(dāng)于shift 1。例如:?
? ? #! /bin/sh
?
? ? echo "The program $0 is now running"
? ? echo "The first parameter is $1"
? ? echo "The second parameter is $2"
? ? echo "The parameter list is $@"
? ? shift
? ? echo "The first parameter is $1"
? ? echo "The second parameter is $2"
? ? echo "The parameter list is $@"
?
shell輸入輸出?
echo?
echo顯示文本行或變量,或者把字符串輸入到文件。?
echo [option] string
-e 解析轉(zhuǎn)義字符
-n 不回車(chē)換行。默認(rèn)情況echo回顯的內(nèi)容后面跟一個(gè)回車(chē)換行。
echo "hello\n\n"
echo -e "hello\n\n"
echo? "hello"
echo -n "hello"
?
管道|?
可以通過(guò)管道把一個(gè)命令的輸出傳遞給另一個(gè)命令做輸入。管道用豎線表示。?
cat myfile | more
ls -l | grep "myfile"
df -k | awk '{print $1}' | grep -v "文件系統(tǒng)"
df -k 查看磁盤(pán)空間,找到第一列,去除“文件系統(tǒng)”,并輸出
?
tee?
tee命令把結(jié)果輸出到標(biāo)準(zhǔn)輸出,另一個(gè)副本輸出到相應(yīng)文件。?
df -k | awk '{print $1}' | grep -v "文件系統(tǒng)" | tee a.txt
?
tee -a a.txt表示追加操作。
df -k | awk '{print $1}' | grep -v "文件系統(tǒng)" | tee -a a.txt
?
文件重定向?
cmd > file? ? ? ? ? ? ?把標(biāo)準(zhǔn)輸出重定向到新文件中
cmd >> file? ? ? ? ? ? 追加
cmd > file 2>&1? ? ? ? 標(biāo)準(zhǔn)出錯(cuò)也重定向到1所指向的file里
cmd >> file 2>&1
cmd < file1 > file2? ? 輸入輸出都定向到文件里
cmd < &fd? ? ? ? ? ? ? 把文件描述符fd作為標(biāo)準(zhǔn)輸入
cmd > &fd? ? ? ? ? ? ? 把文件描述符fd作為標(biāo)準(zhǔn)輸出
cmd < &-? ? ? ? ? ? ? ?關(guān)閉標(biāo)準(zhǔn)輸入
?
函數(shù)?
和C語(yǔ)言類(lèi)似,Shell中也有函數(shù)的概念,但是函數(shù)定義中沒(méi)有返回值也沒(méi)有參數(shù)列表。例如:?
? ? #! /bin/sh
?
? ? foo(){ echo "Function foo is called";}
? ? echo "-=start=-"
? ? foo
? ? echo "-=end=-"
?
注意函數(shù)體的左花括號(hào)'{'和后面的命令之間必須有空格或換行,如果將最后一條命令和右花括號(hào)'}'寫(xiě)在同一行,命令末尾必須有;號(hào)。?
在定義foo()函數(shù)時(shí)并不執(zhí)行函數(shù)體中的命令,就像定義變量一樣,只是給foo這個(gè)名字一個(gè)定義,到后面調(diào)用foo函數(shù)的時(shí)候(注意Shell中的函數(shù)調(diào)用不寫(xiě)括號(hào))才執(zhí)行函數(shù)體中的命令。Shell腳本中的函數(shù)必須先定義后調(diào)用,一般把函數(shù)定義都寫(xiě)在腳本的前面,把函數(shù)調(diào)用和其它命令寫(xiě)在腳本的最后(類(lèi)似C語(yǔ)言中的main函數(shù),這才是整個(gè)腳本實(shí)際開(kāi)始執(zhí)行命令的地方)。?
Shell函數(shù)沒(méi)有參數(shù)列表并不表示不能傳參數(shù),事實(shí)上,函數(shù)就像是迷你腳本,調(diào)用函數(shù)時(shí)可以傳任意個(gè)參數(shù),在函數(shù)內(nèi)同樣是用$0、$1、$2等變量來(lái)提取參數(shù),函數(shù)中的位置參數(shù)相當(dāng)于函數(shù)的局部變量,改變這些變量并不會(huì)影響函數(shù)外面的$0、$1、$2等變量。函數(shù)中可以用return命令返回,如果return后面跟一個(gè)數(shù)字則表示函數(shù)的Exit Status。?
下面這個(gè)腳本可以一次創(chuàng)建多個(gè)目錄,各目錄名通過(guò)命令行參數(shù)傳入,腳本逐個(gè)測(cè)試各目錄是否存在,如果目錄不存在,首先打印信息然后試著創(chuàng)建該目錄。?
? ? #! /bin/sh
?
? ? is_directory()
? ? {
? ? ? DIR_NAME=$1
? ? ? if [ ! -d $DIR_NAME ]; then
? ? ? ? return 1
? ? ? else
? ? ? ? return 0
? ? ? fi
? ? }
?
? ? for DIR in "$@"; do
? ? ? if is_directory "$DIR"
? ? ? then :
? ? ? else
? ? ? ? echo "$DIR doesn't exist. Creating it now..."
? ? ? ? mkdir $DIR > /dev/null 2>&1
? ? ? ? if [ $? -ne 0 ]; then
? ? ? ? ? echo "Cannot create directory $DIR"
? ? ? ? ? exit 1
? ? ? ? fi
? ? ? fi
? ? done
?
注意is_directory()返回0表示真返回1表示假。?
Shell腳本的調(diào)試方法?
Shell提供了一些用于調(diào)試腳本的選項(xiàng),如下所示:?
-n?
讀一遍腳本中的命令但不執(zhí)行,用于檢查腳本中的語(yǔ)法錯(cuò)誤?
-v?
一邊執(zhí)行腳本,一邊將執(zhí)行過(guò)的腳本命令打印到標(biāo)準(zhǔn)錯(cuò)誤輸出?
-x?
提供跟蹤執(zhí)行信息,將執(zhí)行的每一條命令和結(jié)果依次打印出來(lái)?
使用這些選項(xiàng)有三種方法,一是在命令行提供參數(shù)?
? ? $ sh -x ./script.sh
?
二是在腳本開(kāi)頭提供參數(shù)?
? ? #! /bin/sh -x
?
第三種方法是在腳本中用set命令啟用或禁用參數(shù)?
? ? #! /bin/sh
? ? if [ -z "$1" ]; then
? ? ? set -x
? ? ? echo "ERROR: Insufficient Args."
? ? ? exit 1
? ? ? set +x
? ? fi
?
set -x和set +x分別表示啟用和禁用-x參數(shù),這樣可以只對(duì)腳本中的某一段進(jìn)行跟蹤調(diào)試。?
正則表達(dá)式?
以前我們用grep在一個(gè)文件中找出包含某些字符串的行,比如在頭文件中找出一個(gè)宏定義。其實(shí)grep還可以找出符合某個(gè)模式(Pattern)的一類(lèi)字符串。例如找出所有符合x(chóng)xxxx@xxxx.xxx模式的字符串(也就是email地址),要求x字符可以是字母、數(shù)字、下劃線、小數(shù)點(diǎn)或減號(hào),email地址的每一部分可以有一個(gè)或多個(gè)x字符,例如abc.d@ef.com、1_2@987-6.54,當(dāng)然符合這個(gè)模式的不全是合法的email地址,但至少可以做一次初步篩選,篩掉a.b、c@d等肯定不是email地址的字符串。再比如,找出所有符合yyy.yyy.yyy.yyy模式的字符串(也就是IP地址),要求y是0-9的數(shù)字,IP地址的每一部分可以有1-3個(gè)y字符。?
如果要用grep查找一個(gè)模式,如何表示這個(gè)模式,這一類(lèi)字符串,而不是一個(gè)特定的字符串呢?從這兩個(gè)簡(jiǎn)單的例子可以看出,要表示一個(gè)模式至少應(yīng)該包含以下信息:?
字符類(lèi)(Character Class):如上例的x和y,它們?cè)谀J街斜硎疽粋€(gè)字符,但是取值范圍是一類(lèi)字符中的任意一個(gè)。?
數(shù)量限定符(Quantifier): 郵件地址的每一部分可以有一個(gè)或多個(gè)x字符,IP地址的每一部分可以有1-3個(gè)y字符?
各種字符類(lèi)以及普通字符之間的位置關(guān)系:例如郵件地址分三部分,用普通字符@和.隔開(kāi),IP地址分四部分,用.隔開(kāi),每一部分都可以用字符類(lèi)和數(shù)量限定符描述。為了表示位置關(guān)系,還有位置限定符(Anchor)的概念,將在下面介紹。?
規(guī)定一些特殊語(yǔ)法表示字符類(lèi)、數(shù)量限定符和位置關(guān)系,然后用這些特殊語(yǔ)法和普通字符一起表示一個(gè)模式,這就是正則表達(dá)式(Regular Expression)。例如email地址的正則表達(dá)式可以寫(xiě)成[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+.[a-zA-Z0-9_.-]+,IP地址的正則表達(dá)式可以寫(xiě)成[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}。下一節(jié)介紹正則表達(dá)式的語(yǔ)法,我們先看看正則表達(dá)式在grep中怎么用。例如有這樣一個(gè)文本文件testfile:?
192.168.1.1
1234.234.04.5678
123.4234.045.678
abcde
?
查找其中包含IP地址的行:?
$ egrep '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' testfile
192.168.1.1
1234.234.04.5678
?
egrep相當(dāng)于grep -E,表示采用Extended正則表達(dá)式語(yǔ)法。grep的正則表達(dá)式有Basic和Extended兩種規(guī)范,它們之間的區(qū)別下一節(jié)再解釋。另外還有fgrep命令,相當(dāng)于grep -F,表示只搜索固定字符串而不搜索正則表達(dá)式模式,不會(huì)按正則表達(dá)式的語(yǔ)法解釋后面的參數(shù)。?
注意正則表達(dá)式參數(shù)用單引號(hào)括起來(lái)了,因?yàn)檎齽t表達(dá)式中用到的很多特殊字符在Shell中也有特殊含義(例如\),只有用單引號(hào)括起來(lái)才能保證這些字符原封不動(dòng)地傳給grep命令,而不會(huì)被Shell解釋掉。?
192.168.1.1符合上述模式,由三個(gè).隔開(kāi)的四段組成,每段都是1到3個(gè)數(shù)字,所以這一行被找出來(lái)了,可為什么1234.234.04.5678也被找出來(lái)了呢?因?yàn)間rep找的是包含某一模式的行,這一行包含一個(gè)符合模式的字符串234.234.04.567。相反,123.4234.045.678這一行不包含符合模式的字符串,所以不會(huì)被找出來(lái)。?
grep是一種查找過(guò)濾工具,正則表達(dá)式在grep中用來(lái)查找符合模式的字符串。其實(shí)正則表達(dá)式還有一個(gè)重要的應(yīng)用是驗(yàn)證用戶(hù)輸入是否合法,例如用戶(hù)通過(guò)網(wǎng)頁(yè)表單提交自己的email地址,就需要用程序驗(yàn)證一下是不是合法的email地址,這個(gè)工作可以在網(wǎng)頁(yè)的Javascript中做,也可以在網(wǎng)站后臺(tái)的程序中做,例如PHP、Perl、Python、Ruby、Java或C,所有這些語(yǔ)言都支持正則表達(dá)式,可以說(shuō),目前不支持正則表達(dá)式的編程語(yǔ)言實(shí)在很少見(jiàn)。除了編程語(yǔ)言之外,很多UNIX命令和工具也都支持正則表達(dá)式,例如grep、vi、sed、awk、emacs等等。“正則表達(dá)式”就像“變量”一樣,它是一個(gè)廣泛的概念,而不是某一種工具或編程語(yǔ)言的特性。?
基本語(yǔ)法?
我們知道C的變量和Shell腳本變量的定義和使用方法很不相同,表達(dá)能力也不相同,C的變量有各種類(lèi)型,而Shell腳本變量都是字符串。同樣道理,各種工具和編程語(yǔ)言所使用的正則表達(dá)式規(guī)范的語(yǔ)法并不相同,表達(dá)能力也各不相同,有的正則表達(dá)式規(guī)范引入很多擴(kuò)展,能表達(dá)更復(fù)雜的模式,但各種正則表達(dá)式規(guī)范的基本概念都是相通的。本節(jié)介紹egrep(1)所使用的正則表達(dá)式,它大致上符合POSIX正則表達(dá)式規(guī)范,詳見(jiàn)regex(7)(看這個(gè)man page對(duì)你的英文絕對(duì)是很好的鍛煉)。希望讀者仿照上一節(jié)的例子,一邊學(xué)習(xí)語(yǔ)法,一邊用egrep命令做實(shí)驗(yàn)。?
字符類(lèi)?
字符? 含義? ? ? ? ? ? ? ?舉例
.? ?匹配任意一個(gè)字符? ? ? ? ? abc.可以匹配abcd、abc9等
[]? 匹配括號(hào)中的任意一個(gè)字符? [abc]d可以匹配ad、bd或cd
-? ?在[]括號(hào)內(nèi)表示字符范圍? ? [0-9a-fA-F]可以匹配一位十六進(jìn)制數(shù)字
^? ?位于[]括號(hào)內(nèi)的開(kāi)頭,匹配除括號(hào)中的字符之外的任意一個(gè)字符? [^xy]匹配除xy之外的任一字符,因此[^xy]1可以匹配a1、b1但不匹配x1、y1
?
[[:xxx:]]? ?grep工具預(yù)定義的一些命名字符類(lèi)? ?[[:alpha:]]匹配一個(gè)字母,[[:digit:]]匹配一個(gè)數(shù)字
?
數(shù)量限定符?
字符? ? 含義? ? ? ? ? ? ? ? ? ? ? ? ? ? ?舉例
?? ?緊跟在它前面的單元應(yīng)匹配零次或一次? ? [0-9]?\.[0-9]匹配0.0、2.3、.5等,由于.在正則表達(dá)式中是一個(gè)特殊字符,所以需要用\轉(zhuǎn)義一下,取字面值
+? ?緊跟在它前面的單元應(yīng)匹配一次或多次? ? [a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+匹配email地址
*? ?緊跟在它前面的單元應(yīng)匹配零次或多次? ? [0-9][0-9]*匹配至少一位數(shù)字,等價(jià)于[0-9]+,[a-zA-Z_]+[a-zA-Z_0-9]*匹配C語(yǔ)言的標(biāo)識(shí)符
{N} 緊跟在它前面的單元應(yīng)精確匹配N(xiāo)次? ? ? ?[1-9][0-9]{2}匹配從100到999的整數(shù)
{N,}? 緊跟在它前面的單元應(yīng)匹配至少N次? ? ?[1-9][0-9]{2,}匹配三位以上(含三位)的整數(shù)
{,M}? 緊跟在它前面的單元應(yīng)匹配最多M次? ? ?[0-9]{,1}相當(dāng)于[0-9]?
{N,M} 緊跟在它前面的單元應(yīng)匹配至少N次,最多M次? ?[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}匹配IP地址
?
再次注意grep找的是包含某一模式的行,而不是完全匹配某一模式的行。再舉個(gè)例子,如果文本文件的內(nèi)容是?
aaabc
aad
efg
?
查找a*這個(gè)模式的結(jié)果是三行都被找出來(lái)了?
$ egrep 'a*' testfile?
aabc
aad
efg
?
a匹配0個(gè)或多個(gè)a,而第三行包含0個(gè)a,所以也包含了這一模式。單獨(dú)用a這樣的正則表達(dá)式做查找沒(méi)什么意義,一般是把a(bǔ)*作為正則表達(dá)式的一部分來(lái)用。?
位置限定符?
? ? 字符? 含義? ? ? ? ? ? ? ? 舉例
? ? ^? ?匹配行首的位置? ? ? ? ^Content匹配位于一行開(kāi)頭的Content
? ? $? ?匹配行末的位置? ? ? ? ;$匹配位于一行結(jié)尾的;號(hào),^$匹配空行
? ? \<? 匹配單詞開(kāi)頭的位置? ? \<th匹配... this,但不匹配ethernet、tenth
? ? \>? 匹配單詞結(jié)尾的位置? ? p\>匹配leap ...,但不匹配parent、sleepy
? ? \b? 匹配單詞開(kāi)頭或結(jié)尾的位置? ? ?\bat\b匹配... at ...,但不匹配cat、atexit、batch
? ? \B? 匹配非單詞開(kāi)頭和結(jié)尾的位置? ?\Bat\B匹配battery,但不匹配... attend、hat ...
?
位置限定符可以幫助grep更準(zhǔn)確地查找,例如上一節(jié)我們用[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}查找IP地址,找到這兩行?
192.168.1.1
1234.234.04.5678
?
如果用^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$查找,就可以把1234.234.04.5678這一行過(guò)濾掉了。?
其它特殊字符?
字符? 含義? ? 舉例
\? ? 轉(zhuǎn)義字符,普通字符轉(zhuǎn)義為特殊字符,特殊字符轉(zhuǎn)義為普通字符? ?普通字符<寫(xiě)成\<表示單詞開(kāi)頭的位置,特殊字符.寫(xiě)成\.以及\寫(xiě)成\\就當(dāng)作普通字符來(lái)匹配
()? ?將正則表達(dá)式的一部分括起來(lái)組成一個(gè)單元,可以對(duì)整個(gè)單元使用數(shù)量限定符? ? ([0-9]{1,3}\.){3}[0-9]{1,3}匹配IP地址
|? ? 連接兩個(gè)子表達(dá)式,表示或的關(guān)系? ? ?n(o|either)匹配no或neither
?
以上介紹的是grep正則表達(dá)式的Extended規(guī)范,Basic規(guī)范也有這些語(yǔ)法,只是字符?+{}|()應(yīng)解釋為普通字符,要表示上述特殊含義則需要加\轉(zhuǎn)義。如果用grep而不是egrep,并且不加-E參數(shù),則應(yīng)該遵照Basic規(guī)范來(lái)寫(xiě)正則表達(dá)式。?
grep?
1.作用?
Linux系統(tǒng)中g(shù)rep命令是一種強(qiáng)大的文本搜索工具,它能使用正則表達(dá)式搜索文本,并把匹 配的行打印出來(lái)。grep全稱(chēng)是Global Regular Expression Print,表示全局正則表達(dá)式版本,它的使用權(quán)限是所有用戶(hù)。?
grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的擴(kuò)展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它們把所有的字母都看作單詞,也就是說(shuō),正則表達(dá)式中的元字符表示回其自身的字面意義,不再特殊。linux使用GNU版本的grep。它功能更強(qiáng),可以通過(guò)-G、-E、-F命令行選項(xiàng)來(lái)使用egrep和fgrep的功能。?
2.格式?
grep [options]
?
3.主要參數(shù)?
grep --help
?
[options]主要參數(shù):
-c:只輸出匹配行的計(jì)數(shù)。
-i:不區(qū)分大小寫(xiě)。
-h:查詢(xún)多文件時(shí)不顯示文件名。
-l:查詢(xún)多文件時(shí)只輸出包含匹配字符的文件名。
-n:顯示匹配行及 行號(hào)。
-s:不顯示不存在或無(wú)匹配文本的錯(cuò)誤信息。
-v:顯示不包含匹配文本的所有行。
--color=auto :可以將找到的關(guān)鍵詞部分加上顏色的顯示。
?
pattern正則表達(dá)式主要參數(shù):?
\: 忽略正則表達(dá)式中特殊字符的原有含義。
^:匹配正則表達(dá)式的開(kāi)始行。
$: 匹配正則表達(dá)式的結(jié)束行。
\<:從匹配正則表達(dá) 式的行開(kāi)始。
\>:到匹配正則表達(dá)式的行結(jié)束。
[ ]:單個(gè)字符,如[A]即A符合要求 。
[ - ]:范圍,如[A-Z],即A、B、C一直到Z都符合要求 。
.:所有的單個(gè)字符。
*:有字符,長(zhǎng)度可以為0。
?
4.grep命令使用簡(jiǎn)單實(shí)例?
$ grep ‘test’ d*
顯示所有以d開(kāi)頭的文件中包含 test的行。
?
$ grep ‘test’ aa bb cc
顯示在aa,bb,cc文件中匹配test的行。
?
$ grep ‘[a-z]\{5\}’ aa
顯示所有包含每個(gè)字符串至少有5個(gè)連續(xù)小寫(xiě)字符的字符串的行。
?
$ grep ‘w\(es\)t.*\1′ aa
如果west被匹配,則es就被存儲(chǔ)到內(nèi)存中,并標(biāo)記為1,然后搜索任意個(gè)字符(.*),這些字符后面緊跟著 另外一個(gè)es(\1),找到就顯示該行。如果用egrep或grep -E,就不用”\”號(hào)進(jìn)行轉(zhuǎn)義,直接寫(xiě)成’w(es)t.*\1′就可以了。
?
5.grep命令使用復(fù)雜實(shí)例?
明確要求搜索子目錄:?
grep -r
?
或忽略子目錄:?
grep -d skip
?
如果有很多輸出時(shí),您可以通過(guò)管道將其轉(zhuǎn)到’less’上閱讀:?
$ grep magic /usr/src/Linux/Documentation/* | less
?
這樣,您就可以更方便地閱讀。?
有一點(diǎn)要注意,您必需提供一個(gè)文件過(guò)濾方式(搜索全部文件的話(huà)用 *)。如果您忘了,’grep’會(huì)一直等著,直到該程序被中斷。如果您遇到了這樣的情況,按 ,然后再試。?
下面還有一些有意思的命令行參數(shù):?
grep -i pattern files :不區(qū)分大小寫(xiě)地搜索。默認(rèn)情況區(qū)分大小寫(xiě),
grep -l pattern files :只列出匹配的文件名,
grep -L pattern files :列出不匹配的文件名,
grep -w pattern files :只匹配整個(gè)單詞,而不是字符串的一部分(如匹配’magic’,而不是’magical’),
grep -C number pattern files :匹配的上下文分別顯示[number]行,
grep pattern1 | pattern2 files :顯示匹配 pattern1 或 pattern2 的行,
例如:grep "abc\|xyz" testfile? ? 表示過(guò)濾包含abc或xyz的行
grep pattern1 files | grep pattern2 :顯示既匹配 pattern1 又匹配 pattern2 的行。
?
grep -n pattern files? 即可顯示行號(hào)信息
?
grep -c pattern files? 即可查找總行數(shù)
?
這里還有些用于搜索的特殊符號(hào):?
\< 和 \> 分別標(biāo)注單詞的開(kāi)始與結(jié)尾。
例如:
grep man * 會(huì)匹配 ‘Batman’、’manic’、’man’等,
grep ‘\<man’ * 匹配’manic’和’man’,但不是’Batman’,
grep ‘\<man\>’ 只匹配’man’,而不是’Batman’或’manic’等其他的字符串。
‘^’:指匹配的字符串在行首,
‘$’:指匹配的字符串在行 尾,
?
find?
由于find具有強(qiáng)大的功能,所以它的選項(xiàng)也很多,其中大部分選項(xiàng)都值得我們花時(shí)間來(lái)了解一下。即使系統(tǒng)中含有網(wǎng)絡(luò)文件系統(tǒng)( NFS),find命令在該文件系統(tǒng)中同樣有效,只要你具有相應(yīng)的權(quán)限。?
在運(yùn)行一個(gè)非常消耗資源的find命令時(shí),很多人都傾向于把它放在后臺(tái)執(zhí)行,因?yàn)楸闅v一個(gè)大的文件系統(tǒng)可能會(huì)花費(fèi)很長(zhǎng)的時(shí)間(這里是指30G字節(jié)以上的文件系統(tǒng))。?
一、find 命令格式?
1、find命令的一般形式為;?
find pathname -options [-print -exec -ok ...]
?
2、find命令的參數(shù);?
pathname: find命令所查找的目錄路徑。例如用.來(lái)表示當(dāng)前目錄,用/來(lái)表示系統(tǒng)根目錄,遞歸查找。
-print: find命令將匹配的文件輸出到標(biāo)準(zhǔn)輸出。
-exec: find命令對(duì)匹配的文件執(zhí)行該參數(shù)所給出的shell命令。相應(yīng)命令的形式為'command' {? } \;,注意{? ?}和\;之間的空格。
-ok: 和-exec的作用相同,只不過(guò)以一種更為安全的模式來(lái)執(zhí)行該參數(shù)所給出的shell命令,在執(zhí)行每一個(gè)命令之前,都會(huì)給出提示,讓用戶(hù)來(lái)確定是否執(zhí)行。
?
3、find命令選項(xiàng)?
-name? ?按照文件名查找文件。
-perm? ?按照文件權(quán)限來(lái)查找文件。
-prune? 使用這一選項(xiàng)可以使find命令不在當(dāng)前指定的目錄中查找,如果同時(shí)使用-depth選項(xiàng),那么-prune將被find命令忽略。
-user? ?按照文件屬主來(lái)查找文件。
-group? 按照文件所屬的組來(lái)查找文件。
-mtime -n +n 按照文件的更改時(shí)間來(lái)查找文件,-n表示文件更改時(shí)間距現(xiàn)在n天以?xún)?nèi),+n表示文件更改時(shí)間距現(xiàn)在n天以前。find命令還有-atime和-ctime 選項(xiàng),但它們都和-m time選項(xiàng)。
-nogroup 查找無(wú)有效所屬組的文件,即該文件所屬的組在/etc/groups中不存在。
-nouser 查找無(wú)有效屬主的文件,即該文件的屬主在/etc/passwd中不存在。
-newer file1 ! file2 查找更改時(shí)間比文件file1新但比文件file2舊的文件。
-type? ?查找某一類(lèi)型的文件,諸如:
? ? b - 塊設(shè)備文件。
? ? d - 目錄。
? ? c - 字符設(shè)備文件。
? ? p - 管道文件。
? ? l - 符號(hào)鏈接文件。
? ? f - 普通文件。
-size n:[c] 查找文件長(zhǎng)度為n塊的文件,帶有c時(shí)表示文件長(zhǎng)度以字節(jié)計(jì)。
-depth? ?在查找文件時(shí),首先查找當(dāng)前目錄中的文件,然后再在其子目錄中查找。
-fstype? 查找位于某一類(lèi)型文件系統(tǒng)中的文件,這些文件系統(tǒng)類(lèi)型通常可以在配置文件/etc/fstab中找到,該配置文件中包含了本系統(tǒng)中有關(guān)文件系統(tǒng)的信息。
-mount? ?在查找文件時(shí)不跨越文件系統(tǒng)mount點(diǎn)。
-follow? 如果find命令遇到符號(hào)鏈接文件,就跟蹤至鏈接所指向的文件。
?
另外,下面三個(gè)的區(qū)別:?
-amin n? ?查找系統(tǒng)中最后N分鐘訪問(wèn)的文件
-atime n? 查找系統(tǒng)中最后n*24小時(shí)訪問(wèn)的文件
-cmin n? ?查找系統(tǒng)中最后N分鐘被改變文件狀態(tài)的文件
-ctime n? 查找系統(tǒng)中最后n*24小時(shí)被改變文件狀態(tài)的文件
-mmin n? ?查找系統(tǒng)中最后N分鐘被改變文件數(shù)據(jù)的文件
-mtime n? 查找系統(tǒng)中最后n*24小時(shí)被改變文件數(shù)據(jù)的文件
?
4、使用exec或ok來(lái)執(zhí)行shell命令?
使用find時(shí),只要把想要的操作寫(xiě)在一個(gè)文件里,就可以用exec來(lái)配合find查找,很方便 在有些操作系統(tǒng)中只允許-exec選項(xiàng)執(zhí)行諸如ls或ls -l這樣的命令。大多數(shù)用戶(hù)使用這一選項(xiàng)是為了查找舊文件并刪除它們。建議在真正執(zhí)行rm命令刪除文件之前,最好先用ls命令看一下,確認(rèn)它們是所要?jiǎng)h除的文件。?
exec選項(xiàng)后面跟隨著所要執(zhí)行的命令或腳本,然后是一對(duì)兒{},一個(gè)空格和一個(gè)\,最后是一個(gè)分號(hào)。為了使用exec選項(xiàng),必須要同時(shí)使用print選項(xiàng)。如果驗(yàn)證一下find命令,會(huì)發(fā)現(xiàn)該命令只輸出從當(dāng)前路徑起的相對(duì)路徑及文件名。?
例如:為了用ls -l命令列出所匹配到的文件,可以把ls -l命令放在find命令的-exec選項(xiàng)中?
# find . -type f -exec ls -l {} \;
?
上面的例子中,find命令匹配到了當(dāng)前目錄下的所有普通文件,并在-exec選項(xiàng)中使用ls -l命令將它們列出。?
在/logs目錄中查找更改時(shí)間在5日以前的文件并刪除它們:?
$ find logs -type f -mtime +5 -exec rm {} \;
?
記住:在shell中用任何方式刪除文件之前,應(yīng)當(dāng)先查看相應(yīng)的文件,一定要小心!當(dāng)使用諸如mv或rm命令時(shí),可以使用-exec選項(xiàng)的安全模式。它將在對(duì)每個(gè)匹配到的文件進(jìn)行操作之前提示你。?
在下面的例子中, find命令在當(dāng)前目錄中查找所有文件名以.LOG結(jié)尾、更改時(shí)間在5日以上的文件,并刪除它們,只不過(guò)在刪除之前先給出提示。?
$ find . -name "*.conf"? -mtime +5 -ok rm {? } \;
< rm ... ./conf/httpd.conf > ? n
?
按y鍵刪除文件,按n鍵不刪除。?
任何形式的命令都可以在-exec選項(xiàng)中使用。?
在下面的例子中我們使用grep命令。find命令首先匹配所有文件名為“ passwd*”的文件,例如passwd、passwd.old、passwd.bak,然后執(zhí)行g(shù)rep命令看看在這些文件中是否存在一個(gè)itcast用戶(hù)。?
# find /etc -name "passwd*" -exec grep "itcast" {? } \;
?
itcast:x:1000:1000::/home/itcast:/bin/bash
?
選項(xiàng)詳解?
1.使用name選項(xiàng)?
文件名選項(xiàng)是find命令最常用的選項(xiàng),要么單獨(dú)使用該選項(xiàng),要么和其他選項(xiàng)一起使用。?
可以使用某種文件名模式來(lái)匹配文件,記住要用引號(hào)將文件名模式引起來(lái)。?
不管當(dāng)前路徑是什么,如果想要在自己的根目錄$HOME中查找文件名符合*.txt的文件,使用~作為 'pathname'參數(shù),波浪號(hào)~代表了你的$HOME目錄。?
$ find ~ -name "*.txt" -print
?
想要在當(dāng)前目錄及子目錄中查找所有的‘ *.txt’文件,可以用:?
$ find . -name "*.txt" -print
?
想要的當(dāng)前目錄及子目錄中查找文件名以一個(gè)大寫(xiě)字母開(kāi)頭的文件,可以用:?
$ find . -name "[A-Z]*" -print
?
想要在/etc目錄中查找文件名以host開(kāi)頭的文件,可以用:?
$ find /etc -name "host*" -print
?
想要查找$HOME目錄中的文件,可以用:?
$ find ~ -name "*" -print 或find . -print
?
要想讓系統(tǒng)高負(fù)荷運(yùn)行,就從根目錄開(kāi)始查找所有的文件:?
$ find / -name "*" -print
?
如果想在當(dāng)前目錄查找文件名以?xún)蓚€(gè)小寫(xiě)字母開(kāi)頭,跟著是兩個(gè)數(shù)字,最后是.txt的文件,下面的命令就能夠返回例如名為ax37.txt的文件:?
$find . -name "[a-z][a-z][0-9][0-9].txt" -print
?
2、用perm選項(xiàng)?
按照文件權(quán)限模式用-perm選項(xiàng),按文件權(quán)限模式來(lái)查找文件的話(huà)。最好使用八進(jìn)制的權(quán)限表示法。?
如在當(dāng)前目錄下查找文件權(quán)限位為755的文件,即文件屬主可以讀、寫(xiě)、執(zhí)行,其他用戶(hù)可以讀、執(zhí)行的文件,可以用:?
$ find . -perm 755 -print
?
還有一種表達(dá)方法:在八進(jìn)制數(shù)字前面要加一個(gè)橫杠-,表示都匹配,如-007就相當(dāng)于777,-006相當(dāng)于666?
# ls -l
# find . -perm 006
# find . -perm -006
?
-perm mode:文件許可正好符合mode
-perm +mode:文件許可部分符合mode
-perm -mode: 文件許可完全符合mode
?
3、忽略某個(gè)目錄?
如果在查找文件時(shí)希望忽略某個(gè)目錄,因?yàn)槟阒滥莻€(gè)目錄中沒(méi)有你所要查找的文件,那么可以使用-prune選項(xiàng)來(lái)指出需要忽略的目錄。在使用-prune選項(xiàng)時(shí)要當(dāng)心,因?yàn)槿绻阃瑫r(shí)使用了-depth選項(xiàng),那么-prune選項(xiàng)就會(huì)被find命令忽略。?
如果希望在/apps目錄下查找文件,但不希望在/apps/bin目錄下查找,可以用:?
$ find /apps -path "/apps/bin" -prune -o -print
?
4、使用find查找文件的時(shí)候怎么避開(kāi)某個(gè)文件目錄?
比如要在/home/itcast目錄下查找不在dir1子目錄之內(nèi)的所有文件?
find /home/itcast -path "/home/itcast/dir1" -prune -o -print
?
避開(kāi)多個(gè)文件夾?
find /home \( -path /home/itcast/f1 -o -path /home/itcast/f2 \) -prune -o -print
?
注意(前的\,注意(后的空格。?
5、使用user和nouser選項(xiàng)?
按文件屬主查找文件,如在$HOME目錄中查找文件屬主為itcast的文件,可以用:?
$ find ~ -user itcast -print
?
在/etc目錄下查找文件屬主為uucp的文件:?
$ find /etc -user uucp -print
?
為了查找屬主帳戶(hù)已經(jīng)被刪除的文件,可以使用-nouser選項(xiàng)。這樣就能夠找到那些屬主在/etc/passwd文件中沒(méi)有有效帳戶(hù)的文件。在使用-nouser選項(xiàng)時(shí),不必給出用戶(hù)名; find命令能夠?yàn)槟阃瓿上鄳?yīng)的工作。?
例如,希望在/home目錄下查找所有的這類(lèi)文件,可以用:?
$ find /home -nouser -print
?
6、使用group和nogroup選項(xiàng)?
就像user和nouser選項(xiàng)一樣,針對(duì)文件所屬于的用戶(hù)組, find命令也具有同樣的選項(xiàng),為了在/apps目錄下查找屬于itcast用戶(hù)組的文件,可以用:?
$ find /apps -group itcast -print
?
要查找沒(méi)有有效所屬用戶(hù)組的所有文件,可以使用nogroup選項(xiàng)。下面的find命令從文件系統(tǒng)的根目錄處查找這樣的文件?
$ find / -nogroup -print
?
7、按照更改時(shí)間或訪問(wèn)時(shí)間等查找文件?
如果希望按照更改時(shí)間來(lái)查找文件,可以使用mtime,atime或ctime選項(xiàng)。如果系統(tǒng)突然沒(méi)有可用空間了,很有可能某一個(gè)文件的長(zhǎng)度在此期間增長(zhǎng)迅速,這時(shí)就可以用mtime選項(xiàng)來(lái)查找這樣的文件。?
用減號(hào)-來(lái)限定更改時(shí)間在距今n日以?xún)?nèi)的文件,而用加號(hào)+來(lái)限定更改時(shí)間在距今n日以前的文件。?
希望在系統(tǒng)根目錄下查找更改時(shí)間在5日以?xún)?nèi)的文件,可以用:?
$ find / -mtime -5 -print
?
為了在/var/adm目錄下查找更改時(shí)間在3日以前的文件,可以用:?
$ find /var/adm -mtime +3 -print
?
8、查找比某個(gè)文件新或舊的文件?
如果希望查找更改時(shí)間比某個(gè)文件新但比另一個(gè)文件舊的所有文件,可以使用-newer選項(xiàng)。它的一般形式為:?
newest_file_name ! oldest_file_name
?
其中,!是邏輯非符號(hào)。
?
9、使用type選項(xiàng)?
在/etc目錄下查找所有的目錄,可以用:?
$ find /etc -type d -print
?
在當(dāng)前目錄下查找除目錄以外的所有類(lèi)型的文件,可以用:?
$ find . ! -type d -print
?
在/etc目錄下查找所有的符號(hào)鏈接文件,可以用?
$ find /etc -type l -print
?
10、使用size選項(xiàng)?
可以按照文件長(zhǎng)度來(lái)查找文件,這里所指的文件長(zhǎng)度既可以用塊(block)來(lái)計(jì)量,也可以用字節(jié)來(lái)計(jì)量。以字節(jié)計(jì)量文件長(zhǎng)度的表達(dá)形式為N c;以塊計(jì)量文件長(zhǎng)度只用數(shù)字表示即可。?
在按照文件長(zhǎng)度查找文件時(shí),一般使用這種以字節(jié)表示的文件長(zhǎng)度,在查看文件系統(tǒng)的大小,因?yàn)檫@時(shí)使用塊來(lái)計(jì)量更容易轉(zhuǎn)換。 在當(dāng)前目錄下查找文件長(zhǎng)度大于1 M字節(jié)的文件:?
$ find . -size +1000000c -print
?
在/home/apache目錄下查找文件長(zhǎng)度恰好為100字節(jié)的文件:?
$ find /home/apache -size 100c -print
?
在當(dāng)前目錄下查找長(zhǎng)度超過(guò)10塊的文件(一塊等于512字節(jié)):?
$ find . -size +10 -print
?
11、使用depth選項(xiàng)?
在使用find命令時(shí),可能希望先匹配所有的文件,再在子目錄中查找。使用depth選項(xiàng)就可以使find命令這樣做。這樣做的一個(gè)原因就是,當(dāng)在使用find命令向磁帶上備份文件系統(tǒng)時(shí),希望首先備份所有的文件,其次再備份子目錄中的文件。?
在下面的例子中, find命令從文件系統(tǒng)的根目錄開(kāi)始,查找一個(gè)名為CON.FILE的文件。?
它將首先匹配所有的文件然后再進(jìn)入子目錄中查找。?
$ find / -name "CON.FILE" -depth -print
?
12、使用mount選項(xiàng)?
在當(dāng)前的文件系統(tǒng)中查找文件(不進(jìn)入其他文件系統(tǒng)),可以使用find命令的mount選項(xiàng)。?
從當(dāng)前目錄開(kāi)始查找位于本文件系統(tǒng)中文件名以XC結(jié)尾的文件:?
$ find . -name "*.XC" -mount -print
?
練習(xí):請(qǐng)找出你10天內(nèi)所訪問(wèn)或修改過(guò)的.c和.cpp文件。?
find命令的例子;?
1、查找當(dāng)前用戶(hù)主目錄下的所有文件:?
下面兩種方法都可以使用?
$ find $HOME -print
$ find ~ -print
?
2、讓當(dāng)前目錄中文件屬主具有讀、寫(xiě)權(quán)限,并且文件所屬組的用戶(hù)和其他用戶(hù)具有讀權(quán)限的文件;?
$ find . -type f -perm 644 -exec ls -l {? } \;
?
3、為了查找系統(tǒng)中所有文件長(zhǎng)度為0的普通文件,并列出它們的完整路徑;?
$ find / -type f -size 0 -exec ls -l {? } \;
?
4、查找/var/logs目錄中更改時(shí)間在7日以前的普通文件,并在刪除之前詢(xún)問(wèn)它們;?
$ find /var/logs -type f -mtime +7 -ok rm {? } \;
?
5、為了查找系統(tǒng)中所有屬于root組的文件;?
$find . -group root -exec ls -l {? } \;
?
6、find命令將刪除當(dāng)目錄中訪問(wèn)時(shí)間在7日以來(lái)、含有數(shù)字后綴的admin.log文件。?
該命令只檢查三位數(shù)字,所以相應(yīng)文件的后綴不要超過(guò)999。先建幾個(gè)admin.log*的文件 ,才能使用下面這個(gè)命令?
$ find . -name "admin.log[0-9][0-9][0-9]" -atime -7? -ok rm {? } \;
?
7、為了查找當(dāng)前文件系統(tǒng)中的所有目錄并排序;?
$ find . -type d | sort
?
三、xargs?
xargs - build and execute command lines from standard input?
在使用find命令的-exec選項(xiàng)處理匹配到的文件時(shí), find命令將所有匹配到的文件一起傳遞給exec執(zhí)行。但有些系統(tǒng)對(duì)能夠傳遞給exec的命令長(zhǎng)度有限制,這樣在find命令運(yùn)行幾分鐘之后,就會(huì)出現(xiàn) 溢出錯(cuò)誤。錯(cuò)誤信息通常是“參數(shù)列太長(zhǎng)”或“參數(shù)列溢出”。這就是xargs命令的用處所在,特別是與find命令一起使用。?
find命令把匹配到的文件傳遞給xargs命令,而xargs命令每次只獲取一部分文件而不是全部,不像-exec選項(xiàng)那樣。這樣它可以先處理最先獲取的一部分文件,然后是下一批,并如此繼續(xù)下去。?
在有些系統(tǒng)中,使用-exec選項(xiàng)會(huì)為處理每一個(gè)匹配到的文件而發(fā)起一個(gè)相應(yīng)的進(jìn)程,并非將匹配到的文件全部作為參數(shù)一次執(zhí)行;這樣在有些情況下就會(huì)出現(xiàn)進(jìn)程過(guò)多,系統(tǒng)性能下降的問(wèn)題,因而效率不高;?
而使用xargs命令則只有一個(gè)進(jìn)程。另外,在使用xargs命令時(shí),究竟是一次獲取所有的參數(shù),還是分批取得參數(shù),以及每一次獲取參數(shù)的數(shù)目都會(huì)根據(jù)該命令的選項(xiàng)及系統(tǒng)內(nèi)核中相應(yīng)的可調(diào)參數(shù)來(lái)確定。?
來(lái)看看xargs命令是如何同find命令一起使用的,并給出一些例子。?
下面的例子查找系統(tǒng)中的每一個(gè)普通文件,然后使用xargs命令來(lái)測(cè)試它們分別屬于哪類(lèi)文 件?
#find . -type f -print | xargs file
?
在當(dāng)前目錄下查找所有用戶(hù)具有讀、寫(xiě)和執(zhí)行權(quán)限的文件,并收回相應(yīng)的寫(xiě)權(quán)限:?
# ls -l
# find . -perm -7 -print | xargs chmod o-w
# ls -l
?
用grep命令在所有的普通文件中搜索hello這個(gè)詞:?
# find . -type f -print | xargs grep "hello"
?
用grep命令在當(dāng)前目錄下的所有普通文件中搜索hello這個(gè)詞:?
# find . -name \* -type f -print | xargs grep "hello"
?
注意,在上面的例子中, \用來(lái)取消find命令中的*在shell中的特殊含義。?
find命令配合使用exec和xargs可以使用戶(hù)對(duì)所匹配到的文件執(zhí)行幾乎所有的命令。?
sed?
sed意為流編輯器(Stream Editor),在Shell腳本和Makefile中作為過(guò)濾器使用非常普遍,也就是把前一個(gè)程序的輸出引入sed的輸入,經(jīng)過(guò)一系列編輯命令轉(zhuǎn)換為另一種格式輸出。sed和vi都源于早期UNIX的ed工具,所以很多sed命令和vi的末行命令是相同的。?
sed命令行的基本格式為?
sed option 'script' file1 file2 ...
sed option -f scriptfile file1 file2 ...
?
選項(xiàng)含義:?
--version? ? ? ? ? ? 顯示sed版本。
--help? ? ? ? ? ? ? ?顯示幫助文檔。
-n,--quiet,--silent? 靜默輸出,默認(rèn)情況下,sed程序在所有的腳本指令執(zhí)行完畢后,將自動(dòng)打印模式空間中的內(nèi)容,這些選項(xiàng)可以屏蔽自動(dòng)打印。
-e script? ? ? ? ? ? 允許多個(gè)腳本指令被執(zhí)行。
-f script-file,?
--file=script-file? ?從文件中讀取腳本指令,對(duì)編寫(xiě)自動(dòng)腳本程序來(lái)說(shuō)很棒!
-i,--in-place? ? ? ? 直接修改源文件,經(jīng)過(guò)腳本指令處理后的內(nèi)容將被輸出至源文件(源文件被修改)慎用!
-l N, --line-length=N 該選項(xiàng)指定l指令可以輸出的行長(zhǎng)度,l指令用于輸出非打印字符。
--posix? ? ? ? ? ? ?禁用GNU sed擴(kuò)展功能。
-r, --regexp-extended? 在腳本指令中使用擴(kuò)展正則表達(dá)式
-s, --separate? ? ? 默認(rèn)情況下,sed將把命令行指定的多個(gè)文件名作為一個(gè)長(zhǎng)的連續(xù)的輸入流。而GNU sed則允許把他們當(dāng)作單獨(dú)的文件,這樣如正則表達(dá)式則不進(jìn)行跨文件匹配。
-u, --unbuffered? ? 最低限度的緩存輸入與輸出。
?
以上僅是sed程序本身的選項(xiàng)功能說(shuō)明,至于具體的腳本指令(即對(duì)文件內(nèi)容做的操作)后面我們會(huì)詳細(xì)描述,這里就簡(jiǎn)單介紹幾個(gè)腳本指令操作作為sed程序的例子。?
a,append? ? ? ? 追加
i,insert? ? ? ? 插入
d,delete? ? ? ? 刪除
s,substitution? 替換
?
如:$ sed "2a itcast" ./testfile 在輸出testfile內(nèi)容的第二行后添加"itcast"。?
$ sed "2,5d" testfile
?
sed處理的文件既可以由標(biāo)準(zhǔn)輸入重定向得到,也可以當(dāng)命令行參數(shù)傳入,命令行參數(shù)可以一次傳入多個(gè)文件,sed會(huì)依次處理。sed的編輯命令可以直接當(dāng)命令行參數(shù)傳入,也可以寫(xiě)成一個(gè)腳本文件然后用-f參數(shù)指定,編輯命令的格式為?
/pattern/action
?
其中pattern是正則表達(dá)式,action是編輯操作。sed程序一行一行讀出待處理文件,如果某一行與pattern匹配,則執(zhí)行相應(yīng)的action,如果一條命令沒(méi)有pattern而只有action,這個(gè)action將作用于待處理文件的每一行。?
常用的sed命令?
/pattern/p? 打印匹配pattern的行
/pattern/d? 刪除匹配pattern的行
/pattern/s/pattern1/pattern2/? ?查找符合pattern的行,將該行第一個(gè)匹配pattern1的字符串替換為pattern2
/pattern/s/pattern1/pattern2/g? 查找符合pattern的行,將該行所有匹配pattern1的字符串替換為pattern2
?
使用p命令需要注意,sed是把待處理文件的內(nèi)容連同處理結(jié)果一起輸出到標(biāo)準(zhǔn)輸出的,因此p命令表示除了把文件內(nèi)容打印出來(lái)之外還額外打印一遍匹配pattern的行。比如一個(gè)文件testfile的內(nèi)容是?
123
abc
456
?
打印其中包含abc的行?
$ sed '/abc/p' testfile
123
abc
abc
456
?
要想只輸出處理結(jié)果,應(yīng)加上-n選項(xiàng),這種用法相當(dāng)于grep命令?
$ sed -n '/abc/p' testfile
abc
?
使用d命令就不需要-n參數(shù)了,比如刪除含有abc的行?
$ sed '/abc/d' testfile
123
456
?
注意,sed命令不會(huì)修改原文件,刪除命令只表示某些行不打印輸出,而不是從原文件中刪去。?
使用查找替換命令時(shí),可以把匹配pattern1的字符串復(fù)制到pattern2中,比如:?
$ sed 's/bc/-&-/' testfile
123
a-bc-
456
pattern2中的&表示原文件的當(dāng)前行中與pattern1相匹配的字符串
?
再比如:?
$ sed 's/\([0-9]\)\([0-9]\)/-\1-~\2~/' testfile
-1-~2~3
abc
-4-~5~6
?
pattern2中的\1表示與pattern1的第一個(gè)()括號(hào)相匹配的內(nèi)容,\2表示與pattern1的第二個(gè)()括號(hào)相匹配的內(nèi)容。sed默認(rèn)使用Basic正則表達(dá)式規(guī)范,如果指定了-r選項(xiàng)則使用Extended規(guī)范,那么()括號(hào)就不必轉(zhuǎn)義了。?
$ sed? 's/yes/no/;s/static/dhcp/'? ./testfile
注:使用分號(hào)隔開(kāi)指令。
?
$ sed -e 's/yes/no/' -e 's/static/dhcp/' testfile
注:使用-e選項(xiàng)。
?
如果testfile的內(nèi)容是?
<html><head><title>Hello World</title></head>
<body>Welcome to the world of regexp!</body></html>
?
現(xiàn)在要去掉所有的HTML標(biāo)簽,使輸出結(jié)果為?
Hello World
Welcome to the world of regexp!
?
怎么做呢?如果用下面的命令?
$ sed 's/<.*>//g' testfile
?
結(jié)果是兩個(gè)空行,把所有字符都過(guò)濾掉了。這是因?yàn)?#xff0c;正則表達(dá)式中的數(shù)量限定符會(huì)匹配盡可能長(zhǎng)的字符串,這稱(chēng)為貪心的(Greedy)。比如sed在處理第一行時(shí),<.*>匹配的并不是或這樣的標(biāo)簽,而是?
<html><head><title>Hello World</title>
?
這樣一整行,因?yàn)檫@一行開(kāi)頭是<,中間是若干個(gè)任意字符,末尾是>。那么這條命令怎么改才對(duì)呢?留給同學(xué)們思考練習(xí)。?
awk?
sed以行為單位處理文件,awk比sed強(qiáng)的地方在于不僅能以行為單位還能以列為單位處理文件。awk缺省的行分隔符是換行,缺省的列分隔符是連續(xù)的空格和Tab,但是行分隔符和列分隔符都可以自定義,比如/etc/passwd文件的每一行有若干個(gè)字段,字段之間以:分隔,就可以重新定義awk的列分隔符為:并以列為單位處理這個(gè)文件。awk實(shí)際上是一門(mén)很復(fù)雜的腳本語(yǔ)言,還有像C語(yǔ)言一樣的分支和循環(huán)結(jié)構(gòu),但是基本用法和sed類(lèi)似,awk命令行的基本形式為:?
awk option 'script' file1 file2 ...
awk option -f scriptfile file1 file2 ...
?
和sed一樣,awk處理的文件既可以由標(biāo)準(zhǔn)輸入重定向得到,也可以當(dāng)命令行參數(shù)傳入,編輯命令可以直接當(dāng)命令行參數(shù)傳入,也可以用-f參數(shù)指定一個(gè)腳本文件,編輯命令的格式為:?
/pattern/{actions}
condition{actions}
?
和sed類(lèi)似,pattern是正則表達(dá)式,actions是一系列操作。awk程序一行一行讀出待處理文件,如果某一行與pattern匹配,或者滿(mǎn)足condition條件,則執(zhí)行相應(yīng)的actions,如果一條awk命令只有actions部分,則actions作用于待處理文件的每一行。比如文件testfile的內(nèi)容表示某商店的庫(kù)存量:?
ProductA? 30
ProductB? 76
ProductC? 55
?
打印每一行的第二列:?
$ awk '{print $2;}' testfile
30
76
55
?
自動(dòng)變量$1、$2分別表示第一列、第二列等,類(lèi)似于Shell腳本的位置參數(shù),而$0表示整個(gè)當(dāng)前行。再比如,如果某種產(chǎn)品的庫(kù)存量低于75則在行末標(biāo)注需要訂貨:?
$ awk '$2<75 {printf "%s\t%s\n", $0, "REORDER";} $2>=75 {print $0;}' testfile
ProductA? 30? ? REORDER
ProductB? 76
ProductC? 55? ? REORDER
?
可見(jiàn)awk也有和C語(yǔ)言非常相似的printf函數(shù)。awk命令的condition部分還可以是兩個(gè)特殊的condition-BEGIN和END,對(duì)于每個(gè)待處理文件,BEGIN后面的actions在處理整個(gè)文件之前執(zhí)行一次,END后面的actions在整個(gè)文件處理完之后執(zhí)行一次。?
awk命令可以像C語(yǔ)言一樣使用變量(但不需要定義變量),比如統(tǒng)計(jì)一個(gè)文件中的空行數(shù)?
$ awk '/^ *$/ {x=x+1;} END {print x;}' testfile
?
就像Shell的環(huán)境變量一樣,有些awk變量是預(yù)定義的有特殊含義的:?
awk常用的內(nèi)建變量?
FILENAME? 當(dāng)前輸入文件的文件名,該變量是只讀的
NR? 當(dāng)前行的行號(hào),該變量是只讀的,R代表record
NF? 當(dāng)前行所擁有的列數(shù),該變量是只讀的,F代表field
OFS 輸出格式的列分隔符,缺省是空格
FS? 輸入文件的列分融符,缺省是連續(xù)的空格和Tab
ORS 輸出格式的行分隔符,缺省是換行符
RS? 輸入文件的行分隔符,缺省是換行符
?
例如打印系統(tǒng)中的用戶(hù)帳號(hào)列表?
$ awk 'BEGIN {FS=":"} {print $1;}' /etc/passwd
?
Linux核心命令?
?
stracenetstatperftoppidstatmpstatdstatvmstatslabtopfreetoptcpdumpipnicstatdtracepingdtraceblktraceiptopiostatstap
文本處理類(lèi)的命令:?
?wc wc [option] [file]...
? ? -l: 統(tǒng)計(jì)行數(shù)
? ? -c: 統(tǒng)計(jì)字節(jié)數(shù)
? ? -w;統(tǒng)計(jì)單詞數(shù)
? tr tr: 轉(zhuǎn)換字符或刪除字符
? ? tr '集合1' '集合2'
? ? tr -d '字符集合'
? cut This is a test line.
-d字符:指定分隔符
-f#: 指定要顯示字段
? ? 單個(gè)數(shù)字:一個(gè)字段
? ? 逗號(hào)分隔的多個(gè)數(shù)字:指定多個(gè)離散字段
? ? -:連續(xù)字段,如3-5;
? sort 按字符進(jìn)行比較
sort [option] file...
? ? -f: 忽略字符大小寫(xiě);
? ? -n: 比較數(shù)值大小;
? ? -t: 指定分隔符
? ? -k: 指定分隔后進(jìn)行比較字段
? ? -u: 重復(fù)的行,只顯示一次;
? uniq 移除重復(fù)的行
-c:顯示每行重復(fù)的次數(shù)
-d:僅顯示重復(fù)過(guò)的行
-u: 僅顯示不曾重復(fù)的行
? 工具速查鏈接 http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/index.html
?
shell習(xí)題訓(xùn)練?
求2個(gè)數(shù)之和計(jì)算1-100的和將一目錄下所有的文件的擴(kuò)展名改為bak編譯當(dāng)前目錄下的所有.c文件:打印root可以使用可執(zhí)行文件數(shù),處理結(jié)果: root's bins: 2306打印當(dāng)前sshd的端口和進(jìn)程id,處理結(jié)果: sshd Port&&pid: 22 5412 輸出本機(jī)創(chuàng)建20000個(gè)目錄所用的時(shí)間,處理結(jié)果: real? ? 0m3.367s
user? ? 0m0.066s
sys? ? ?0m1.925s
? 打印本機(jī)的交換分區(qū)大小,處理結(jié)果: Swap:1024M? 文本分析,取出/etc/password中shell出現(xiàn)的次數(shù) 第一種方法結(jié)果:
? ? ? 4 /bin/bash
? ? ? 1 /bin/sync
? ? ? 1 /sbin/halt
? ? ?31 /sbin/nologin
? ? ? 1 /sbin/shutdown
第二種方法結(jié)果:
? ? ? ? /bin/sync? ? ? ?1
? ? ? ? /bin/bash? ? ? ?1
? ? ? ? /sbin/nologin? ?30
? ? ? ? /sbin/halt? ? ? 1
? ? ? ? /sbin/shutdown? 1
? 文件整理,employee文件中記錄了工號(hào)和姓名,(提示join) employee.txt:
? ? 100 Jason Smith?
? ? 200 John Doe?
? ? 300 Sanjay Gupta?
? ? 400 Ashok Sharma?
? ? bonus文件中記錄工號(hào)和工資
bonus.txt:
? ? 100 $5,000?
? ? 200 $500?
? ? 300 $3,000?
? ? 400 $1,250?
要求把兩個(gè)文件合并并輸出如下,處理結(jié)果:
? ? 400 ashok sharma $1,250
? ? 100 jason smith? $5,000
? ? 200 john doe? $500
? ? 300 sanjay gupta? $3,000
? 寫(xiě)一個(gè)shell腳本來(lái)得到當(dāng)前的日期,時(shí)間,用戶(hù)名和當(dāng)前工作目錄。 編寫(xiě)shell腳本獲取本機(jī)的網(wǎng)絡(luò)地址。編寫(xiě)個(gè)shell腳本將當(dāng)前目錄下大于10K的文件轉(zhuǎn)移到/tmp目錄下 編寫(xiě)一個(gè)名為myfirstshell.sh的腳本,它包括以下內(nèi)容。 a) 包含一段注釋,列出您的姓名、腳本的名稱(chēng)和編寫(xiě)這個(gè)腳本的目的。
b) 問(wèn)候用戶(hù)。
c) 顯示日期和時(shí)間。
d) 顯示這個(gè)月的日歷。
e) 顯示您的機(jī)器名。
f) 顯示當(dāng)前這個(gè)操作系統(tǒng)的名稱(chēng)和版本。
g) 顯示父目錄中的所有文件的列表。
h) 顯示root正在運(yùn)行的所有進(jìn)程。
i) 顯示變量TERM、PATH和HOME的值。
j) 顯示磁盤(pán)使用情況。
k) 用id命令打印出您的組ID。
m) 跟用戶(hù)說(shuō)“Good bye”
? 文件移動(dòng)拷貝,有m1.txt m2.txt m3.txt m4.txt,分別創(chuàng)建出對(duì)應(yīng)的目錄,m1 m2 m3 m4 并把文件移動(dòng)到對(duì)應(yīng)的目錄下 root用戶(hù)今天登陸了多長(zhǎng)時(shí)間終端輸入一個(gè)文件名,判斷是否是設(shè)備文件 統(tǒng)計(jì)IP訪問(wèn):要求分析apache訪問(wèn)日志,找出訪問(wèn)頁(yè)面數(shù)量在前100位的IP數(shù)。日志大小在78M左右。以下是apache的訪問(wèn)日志節(jié)選 202.101.129.218 - - [26/Mar/2006:23:59:55 +0800] "GET /online/stat_inst.php?pid=d065 HTTP/1.1" 302 20-"-" "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
? 設(shè)計(jì)一個(gè)Shell程序,在/userdata目錄下建立50個(gè)目錄,即user1~user50,并設(shè)置每個(gè)目錄的權(quán)限,其中其他用戶(hù)的權(quán)限為:讀;文件所有者的權(quán)限為:讀、寫(xiě)、執(zhí)行;文件所有者所在組的權(quán)限為:讀、執(zhí)行。 設(shè)計(jì)一個(gè)shell程序,添加一個(gè)新組為class1,然后添加屬于這個(gè)組的30個(gè)用戶(hù),用戶(hù)名的形式為stdxx,其中xx從01到30,并設(shè)置密碼為對(duì)應(yīng)的stdxx。編寫(xiě)shell程序,實(shí)現(xiàn)自動(dòng)刪除30個(gè)賬號(hào)的功能。賬號(hào)名為std01至std30。用戶(hù)清理,清除本機(jī)除了當(dāng)前登陸用戶(hù)以外的所有用戶(hù)設(shè)計(jì)一個(gè)shell程序,在每月第一天備份并壓縮/etc目錄的所有內(nèi)容,存放在/root/bak目錄里,且文件名,為如下形式y(tǒng)ymmdd_etc,yy為年,mm為月,dd為日。Shell程序fileback存放在/usr/bin目錄下。對(duì)于一個(gè)用戶(hù)日志文件,每行記錄了一個(gè)用戶(hù)查詢(xún)串,長(zhǎng)度為1-255字節(jié),共幾千萬(wàn)行,請(qǐng)排出查詢(xún)最多的前100條。 日志可以自己構(gòu)造。 (提示:awk sort uniq head)編寫(xiě)自己的ubuntu環(huán)境安裝腳本編寫(xiě)服務(wù)器守護(hù)進(jìn)程管理腳本。 查看TCP連接狀態(tài) netstat -nat |awk ‘{print $6}’|sort|uniq -c|sort -rn
?
netstat -n | awk ‘/^tcp/ {++S[$NF]};END {for(a in S) print a, S[a]}’ 或
netstat -n | awk ‘/^tcp/ {++state[$NF]}; END {for(key in state) print key,"\t",state[key]}’
netstat -n | awk ‘/^tcp/ {++arr[$NF]};END {for(k in arr) print k,"t",arr[k]}’
?
netstat -n |awk ‘/^tcp/ {print $NF}’|sort|uniq -c|sort -rn
?
netstat -ant | awk ‘{print $NF}’ | grep -v ‘[a-z]‘ | sort | uniq -c
? 查找請(qǐng)求數(shù)請(qǐng)20個(gè)IP(常用于查找攻來(lái)源): netstat -anlp|grep 80|grep tcp|awk ‘{print $5}’|awk -F: ‘{print $1}’|sort|uniq -c|sort -nr|head -n20
?
netstat -ant |awk ‘/:80/{split($5,ip,":");++A[ip[1]]}END{for(i in A) print A[i],i}’ |sort -rn|head -n20
? 用tcpdump嗅探80端口的訪問(wèn)看看誰(shuí)最高 tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." ‘{print $1"."$2"."$3"."$4}’ | sort | uniq -c | sort -nr |head -20
? 查找較多time_wait連接 netstat -n|grep TIME_WAIT|awk ‘{print $5}’|sort|uniq -c|sort -rn|head -n20
? 找查較多的SYN連接 netstat -an | grep SYN | awk ‘{print $5}’ | awk -F: ‘{print $1}’ | sort | uniq -c | sort -nr | more
? 根據(jù)端口列進(jìn)程 netstat -ntlp | grep 80 | awk ‘{print $7}’ | cut -d/ -f1
? 獲得訪問(wèn)前10位的ip地址 cat access.log|awk ‘{print $1}’|sort|uniq -c|sort -nr|head -10
cat access.log|awk ‘{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}’
? 訪問(wèn)次數(shù)最多的文件或頁(yè)面,取前20 cat access.log|awk ‘{print $11}’|sort|uniq -c|sort -nr|head -20
? 列出傳輸最大的幾個(gè)exe文件(分析下載站的時(shí)候常用) cat access.log |awk ‘($7~/.exe/){print $10 " " $1 " " $4 " " $7}’|sort -nr|head -20
? 列出輸出大于200000byte(約200kb)的exe文件以及對(duì)應(yīng)文件發(fā)生次數(shù) cat access.log |awk ‘($10 > 200000 && $7~/.exe/){print $7}’|sort -n|uniq -c|sort -nr|head -100
? 如果日志最后一列記錄的是頁(yè)面文件傳輸時(shí)間,則有列出到客戶(hù)端最耗時(shí)的頁(yè)面 cat access.log |awk ‘($7~/.php/){print $NF " " $1 " " $4 " " $7}’|sort -nr|head -100
? 列出最最耗時(shí)的頁(yè)面(超過(guò)60秒的)的以及對(duì)應(yīng)頁(yè)面發(fā)生次數(shù) cat access.log |awk ‘($NF > 60 && $7~/.php/){print $7}’|sort -n|uniq -c|sort -nr|head -100
? 列出傳輸時(shí)間超過(guò) 30 秒的文件 cat access.log |awk ‘($NF > 30){print $7}’|sort -n|uniq -c|sort -nr|head -20
? 統(tǒng)計(jì)網(wǎng)站流量(G) cat access.log |awk ‘{sum+=$10} END {print sum/1024/1024/1024}’
? 統(tǒng)計(jì)404的連接 awk ‘($9 ~/404/)’ access.log | awk ‘{print $9,$7}’ | sort
? 統(tǒng)計(jì)http status cat access.log |awk ‘{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}'
cat access.log |awk '{print $9}'|sort|uniq -c|sort -rn
? 蜘蛛分析,查看是哪些蜘蛛在抓取內(nèi)容。 /usr/sbin/tcpdump -i eth0 -l -s 0 -w - dst port 80 | strings | grep -i user-agent | grep -i -E 'bot|crawler|slurp|spider'
? 創(chuàng)建一個(gè)用戶(hù)mandriva,其ID號(hào)為2002,基本組為distro(組ID為3003),附加組為linux; # groupadd linux
# groupadd -g 3003 distro
# useradd -u 2002 -g distro -G linux mandriva
? 創(chuàng)建一個(gè)用戶(hù)fedora,其全名為Fedora Community,默認(rèn)shell為tcsh; # useradd -c "Fedora Community" -s /bin/tcsh fedora? 修改mandriva的ID號(hào)為4004,基本組為linux,附加組為distro和fedora; # usermod -u 4004 -g linux -G distro,fedora mandriva
? 給fedora加密碼,并設(shè)定其密碼最短使用期限為2天,最長(zhǎng)為50天; # passwd fedora
# chage -m 2 -M 50 fedora
? 調(diào)試命令 strace -p pid
? 寫(xiě)一個(gè)腳本 1、創(chuàng)建一個(gè)組newgroup, id號(hào)為4000;
2、創(chuàng)建一個(gè)用戶(hù)mageedu1, id號(hào)為3001,附加組為newgroup;
3、創(chuàng)建目錄/tmp/hellodirxyz
4、復(fù)制/etc/fstab至上面的目錄中
5、改變目錄及內(nèi)部文件的屬主和屬組為mageedu1;
6、讓目錄及內(nèi)部文件的其它用戶(hù)沒(méi)有任何權(quán)限;
?
? ? ? ? #!/bin/bash
? ? ? ? # Description:
? ? ? ? # Version:
? ? ? ? # Datetime:
? ? ? ? # Author:
?
? ? ? ? myGroup="newgroup1"
? ? ? ? myUser="mageedu2"
? ? ? ? myDir="/tmp/hellodirxyz1"
? ? ? ? myID=3002
?
? ? ? ? groupadd -g 4001 $myGroup
? ? ? ? useradd -u $myID -G $myGroup $myUser
? ? ? ? mkdir $myDir
? ? ? ? cp /etc/fstab $myDir
? ? ? ? chown -R $myUser:$myUser $myDir
? ? ? ? chmod -R o= $myDir
?
? ? ? ? unset myGroup myUser myID myDir
? 統(tǒng)計(jì)/bin、/usr/bin、/sbin和/usr/sbin等各目錄中的文件個(gè)數(shù); # ls /bin | wc -l
? 顯示當(dāng)前系統(tǒng)上所有用戶(hù)的shell,要求,每種shell只顯示一次; # cut -d: -f7 /etc/passwd | sort -u
? 取出/etc/passwd文件的第7行; # head -7 /etc/passwd | tail -1
? 顯示第3題中取出的第7行的用戶(hù)名; # head -7 /etc/passwd | tail -1 | cut -d: -f1
?
# head -7 /etc/passwd | tail -1 | cut -d: -f1 | tr 'a-z' 'A-Z'
? 統(tǒng)計(jì)/etc目錄下以P或p開(kāi)頭的文件個(gè)數(shù); # ls -d /etc/[Pp]* | wc -l
? 寫(xiě)一個(gè)腳本,用for循環(huán)實(shí)現(xiàn)顯示/etc/init.d/functions、/etc/rc.d/rc.sysinit和/etc/fstab各有多少行; for fileName in /etc/init.d/functions /etc/rc.d/rc.sysinit /etc/fstab; do
? ? wc -l $fileName
done
?
#!/bin/bash
for fileName in /etc/init.d/functions /etc/rc.d/rc.sysinit /etc/fstab; do
? ? lineCount=`wc -l $fileName | cut -d' ' -f1`
? ? echo "$fileName: $lineCount lines."
done
?
#!/bin/bash
for fileName in /etc/init.d/functions /etc/rc.d/rc.sysinit /etc/fstab; do
? ? echo "$fileName: `wc -l $fileName | cut -d' ' -f1` lines."
done
? 寫(xiě)一個(gè)腳本,將上一題中三個(gè)文件的復(fù)制到/tmp目錄中;用for循環(huán)實(shí)現(xiàn),分別將每個(gè)文件的最近一次的修改時(shí)間改為2016年12月15號(hào)15點(diǎn)43分; for fileName in /etc/init.d/functions /etc/rc.d/rc.sysinit /etc/fstab; do
? ? cp $fileName /tmp
? ? baseName=`basename $fileName`
? ? touch -m -t 201109151327 /tmp/$baseName
done
? 寫(xiě)一個(gè)腳本, 顯示/etc/passwd中第3、7和11個(gè)用戶(hù)的用戶(hù)名和ID號(hào); for lineNo in 3 7 11; do
? ? userInfo=`head -n $lineNo /etc/passwd | tail -1 | cut -d: -f1,3`
? ? echo -e "User: `echo $userInfo | cut -d: -f1`\nUid: `echo $userInfo |cut -d: -f2`"
done
? 顯示/proc/meminfo文件中以大小寫(xiě)s開(kāi)頭的行; # grep "^[sS]" /proc/meminfo
# grep -i "^s" /proc/meminfo
? 取出默認(rèn)shell為非bash的用戶(hù); # grep -v "bash$" /etc/passwd | cut -d: -f1
? 取出默認(rèn)shell為bash的且其ID號(hào)最大的用戶(hù); # grep "bash$" /etc/passwd | sort -n -t: -k3 | tail -1 | cut -d: -f1
? 顯示/etc/rc.d/rc.sysinit文件中,以#開(kāi)頭,后面跟至少一個(gè)空白字符,而后又有至少一個(gè)非空白字符的行; # grep "^#[[:space:]]\{1,\}[^[:space:]]\{1,\}" /etc/rc.d/rc.sysinit
? 顯示/boot/grub/grub.conf中以至少一個(gè)空白字符開(kāi)頭的行; # grep "^[[:space:]]\{1,\}[^[:space:]]\{1,\}" /boot/grub/grub.conf
? 找出/etc/passwd文件中一位數(shù)或兩位數(shù); # grep --color=auto "\<[0-9]\{1,2\}\>" /etc/passwd
? 找出ifconfig命令結(jié)果中的1到255之間的整數(shù); # ifconfig | grep -E --color=auto "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"
? 查看當(dāng)前系統(tǒng)上root用戶(hù)的所有信息; # grep "^root\>" /etc/passwd
? 添加用戶(hù)bash和testbash、basher,而后找出當(dāng)前系統(tǒng)上其用戶(hù)名和默認(rèn)shell相同的用戶(hù); # grep --color=auto "^\([[:alnum:]]\{1,\}\)\>.*\1$" /etc/passwd
? 找出netstat -tan命令執(zhí)行的結(jié)果中以“LISTEN”或“ESTABLISHED”結(jié)尾的行; 取出當(dāng)前系統(tǒng)上所有用戶(hù)的shell,要求:每種shell只顯示一次,且按升序顯示; # cut -d: -f7 /etc/passwd | sort -u
?
自動(dòng)化?
開(kāi)機(jī)自啟動(dòng)腳本?
如果要添加為開(kāi)機(jī)啟動(dòng)執(zhí)行的腳本文件,可先將腳本復(fù)制或者軟連接到/etc/init.d/目錄下,然后用:?
? ? update-rc.d xxx defaults NN命令(NN為啟動(dòng)順序),
?
將腳本添加到初始化執(zhí)行的隊(duì)列中去。?
注意如果腳本需要用到網(wǎng)絡(luò),則NN需設(shè)置一個(gè)比較大的數(shù)字,如99。?
1) 將你的啟動(dòng)腳本復(fù)制到 /etc/init.d目錄下,以下假設(shè)你的腳本文件名為 test。?
2) 設(shè)置腳本文件的權(quán)限?
? ? $ sudo chmod 755 /etc/init.d/test
?
3) 執(zhí)行如下命令將腳本放到啟動(dòng)腳本中去:?
? ? $ cd /etc/init.d
? ? $ sudo update-rc.d test defaults 95
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的[转载] Python学习笔记——运维和Shell的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: c语言i++和++i程序_使用C ++程
- 下一篇: [转载] python中for语句用法_