- 論壇徽章:
- 0
|
Shell的魅力
[這個(gè)貼子最后由michaelds在 2002/03/21 10:06pm 編輯]
這個(gè)程序包含的知識(shí)點(diǎn)比較多,如果不是在這些點(diǎn)方面均有了解的話,理解起來會(huì)比較困難。但是仔細(xì)分析搞懂,還是很有收獲的。因此在這里細(xì)細(xì)解讀一下:
程序目的:
對(duì)指定的目錄,顯示該目錄及其下所有子目錄所占用的空間。顯示方式上,要求以類windows樹狀結(jié)構(gòu)的方式表現(xiàn)目錄和子目錄的關(guān)系,顯示空間大小用(?kb)的樣式說明。
程序代碼:
(1)#!/sbin/ksh
(2)dir=${1:-.}
(3)(cd $dir;pwd)
(4)find $dir -type d -print | du | awk '{print $2, "== ("$1/2"kb)"}' |sort -f | sed -e "s,[^ /]*/\([^ /]*\) ==,\|--\1," -e"s,[^ /]*/,| ,g"
(1)表明使用的shell解釋器為ksh
(2)對(duì)變量dir賦值,如果執(zhí)行該程序時(shí)指定了第一參數(shù)$1,那么dir的值即為$1(即指定目錄),如果沒有指定參數(shù),那么dir的值為"."(即當(dāng)前目錄)。這種變量設(shè)置的模式還有=value、+value、 value、?value、:=value、:-value,各有其功能。
(3)為了首先顯示一下處理的路徑所在的主目錄,需要進(jìn)至該目錄,然后用pwd命令顯示出來。用()括起來,表示這兩句作為一組命令一起執(zhí)行,而且有個(gè)重要的好處就是執(zhí)行完后不會(huì)影響程序的當(dāng)前路徑,可以理解是()使其內(nèi)部命令在一子shell中運(yùn)行,一旦執(zhí)行完畢便恢復(fù)原shell的環(huán)境。
(4)這句是關(guān)鍵。
首先find $dir -type d -print表明要把$dir指定的目錄下所有的子目錄都找到并顯示出來。-type d說明找的是目錄而不是文件。
然后,使用du命令顯示每一目錄所占空間由于du命令顯示的單位是512字節(jié)塊,因此要將得到的值除以2,得到kb值。根據(jù)du的輸出結(jié)果,第二列是目錄,第一列是值,因此使用awk分別處理,$1/2的表達(dá)式要用引號(hào)引起是要讓awk正確識(shí)別表達(dá)式。
sort -f是要把輸出的結(jié)果排序,按字母順序排序,便于使用的人察看。使用-f可以讓sh排序時(shí)對(duì)大小寫不敏感。
sed一句是關(guān)鍵中的關(guān)鍵,-e的寫法可以使sed連續(xù)執(zhí)行多套命令,此處有兩個(gè)-e。來看命令集:s打頭,表明了是一個(gè)替換任務(wù),跟我們熟悉的不同,我們平時(shí)用s/aa/bb/這樣的形式較多,但對(duì)于sed來說,分隔符是可以自行任意指定的,這里sed將跟在s命令后的","作為了分隔符。于是就有了s,...,...,的樣子。
我們知道格式是“s/源串/目標(biāo)串/”,那么第一組命令,源串是說什么呢?[]的用法在sed中表示:取[]字符組中的一個(gè)字符,而[]中的第一位若是"^",則表示不取后面的任何一個(gè)字符。那么[^ /]*/就表示匹配這樣的格式:"由不是空格或/的一個(gè)或多個(gè)字符組成的串,后面緊跟一個(gè)/",接下來有\(zhòng)(......\)的格式,這種格式用在源串中,表示用這種符號(hào)括注的部分要sed記住,而且sed會(huì)給這個(gè)部分自動(dòng)起個(gè)名字叫\(zhòng)1,如果在源串中還有這樣的標(biāo)記,就依次命名為\2,\3......。這\1要sed記住什么呢?是"[^ /]*",這還是說"由不是空格或/的一個(gè)或多個(gè)字符組成的串"。\1之后還有" =="也是源串中要求匹配的。再來看目標(biāo)串,就是要替換成的串,是"\|--\1",作者認(rèn)為"|"是特殊字符,所以前跟\號(hào)(其實(shí)不必)。"--"是普通符號(hào)了,\1就是我們剛才在源串中要求標(biāo)記的部分,換到這里來。
第二組命令簡(jiǎn)單一些。源串:"[^ /]*/",仍然是"由不是空格或/的一個(gè)或多個(gè)字符組成的串,后面緊跟一個(gè)/",目標(biāo)串是"| ",最后一個(gè)g表明全行替換,就是說如果在一行中有多處匹配源串,都要替換成目標(biāo)串。
再?gòu)脑摮绦驊?yīng)用的角度看這一句的功能:
作者是要把這樣的顯示結(jié)果
. == (904724kb)
./bak == (1kb)
./billfile == (1kb)
./bin == (11646kb)
./bin/images == (16kb)
....................
替換成這樣的結(jié)果
. == (904724kb)
|--bak (1kb)
|--billfile (1kb)
|--bin (11646kb)
| |--images (16kb)
....................
對(duì)于"aaa/xxxx/yyyy =="分解這一要求,實(shí)際是兩步,先把"xxxx/yyyy =="替換為"|--yyyy",然后將aaa變成"| "(如沒有aaa則無行為),在aaa中含有幾個(gè)/,就換成幾個(gè)"| "。這里的sed命令恰好完成了這一功能。
程序改進(jìn):
(1)實(shí)際該程序沒有使用ksh的任何特殊功能,改為sh仍可正常運(yùn)行,兼容性會(huì)更好。
(2)先find再du是沒有必要的。因?yàn)閐u本身就能尋找子目錄,且自動(dòng)顯示每個(gè)子目錄的大小。另外,如果對(duì)指定的目錄無讀權(quán)限的話,find就會(huì)報(bào)出錯(cuò),但直接用du則沒事。
(3)"|"在sed中不是特殊字符不必再用"\"轉(zhuǎn)義了。
最后我的建議結(jié)果如下:
#!/bin/sh
dir=${1:-.}
(cd $dir;pwd)
du $dir| awk '{print $2, "== ("$1/2"kb)"}' |sort -f|sed -e "s,[^ /]*/\([^ /]*\) ==,|--\1," -e "s,[^ /]*/,| ,g"
|
|