天天看點

一段檔案相關的shell腳本解讀

CODE:

#!/sbin/ksh

dir=${1:-.}

(cd $dir;pwd)

find $dir -type d -print | du | awk '{print $2, "== ("$1/2"kb)"}' |sort -f |

sed -e "s,[^ /]*/\([^ /]*\) ==,\|--\1," -e"s,[^ /]*/,| ,g"

#The End

感覺有些難度,不知哪位大俠能夠給在下解釋一下!

作者: feeling    時間: 2002-3-21 20:59     标題: Shell的魅力

第五行是緊跟在第四行之後的,由于太長被強制換行了。

作者: michaelds    時間: 2002-3-21 21:55     标題: Shell的魅力

[這個貼子最後由michaelds在 2002/03/21 10:06pm 編輯]

這個程式包含的知識點比較多,如果不是在這些點方面均有了解的話,了解起來會比較困難。但是仔細分析搞懂,還是很有收獲的。是以在這裡細細解讀一下:

程式目的:

對指定的目錄,顯示該目錄及其下所有子目錄所占用的空間。顯示方式上,要求以類windows樹狀結構的方式表現目錄和子目錄的關系,顯示空間大小用(?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)對變量dir指派,如果執行該程式時指定了第一參數$1,那麼dir的值即為$1(即指定目錄),如果沒有指定參數,那麼dir的值為"."(即目前目錄)。這種變量設定的模式還有=value、+value、:?value、?value、:=value、:-value,各有其功能。

(3)為了首先顯示一下處理的路徑所在的主目錄,需要進至該目錄,然後用pwd指令顯示出來。用()括起來,表示這兩句作為一組指令一起執行,而且有個重要的好處就是執行完後不會影響程式的目前路徑,可以了解是()使其内部指令在一子shell中運作,一旦執行完畢便恢複原shell的環境。

(4)這句是關鍵。

首先find $dir -type d -print表明要把$dir指定的目錄下所有的子目錄都找到并顯示出來。-type d說明找的是目錄而不是檔案。

然後,使用du指令顯示每一目錄所占空間由于du指令顯示的機關是512位元組塊,是以要将得到的值除以2,得到kb值。根據du的輸出結果,第二列是目錄,第一列是值,是以使用awk分别處理,$1/2的表達式要用引号引起是要讓awk正确識别表達式。

sort -f是要把輸出的結果排序,按字母順序排序,便于使用的人察看。使用-f可以讓sh排序時對大小寫不敏感。

sed一句是關鍵中的關鍵,-e的寫法可以使sed連續執行多套指令,此處有兩個-e。來看指令集:s打頭,表明了是一個替換任務,跟我們熟悉的不同,我們平時用s/aa/bb/這樣的形式較多,但對于sed來說,分隔符是可以自行任意指定的,這裡sed将跟在s指令後的","作為了分隔符。于是就有了s,...,...,的樣子。

我們知道格式是“s/源串/目标串/”,那麼第一組指令,源串是說什麼呢?[]的用法在sed中表示:取[]字元組中的一個字元,而[]中的第一位若是"^",則表示不取後面的任何一個字元。那麼[^ /]*/就表示比對這樣的格式:"由不是空格或/的一個或多個字元組成的串,後面緊跟一個/",接下來有\(......\)的格式,這種格式用在源串中,表示用這種符号括注的部分要sed記住,而且sed會給這個部分自動起個名字叫\1,如果在源串中還有這樣的标記,就依次命名為\2,\3......。這\1要sed記住什麼呢?是"[^

/]*",這還是說"由不是空格或/的一個或多個字元組成的串"。\1之後還有" =="也是源串中要求比對的。再來看目标串,就是要替換成的串,是"\|--\1",作者認為"|"是特殊字元,是以前跟\号(其實不必)。"--"是普通符号了,\1就是我們剛才在源串中要求标記的部分,換到這裡來。

第二組指令簡單一些。源串:"[^ /]*/",仍然是"由不是空格或/的一個或多個字元組成的串,後面緊跟一個/",目标串是"| ",最後一個g表明全行替換,就是說如果在一行中有多處比對源串,都要替換成目标串。

再從該程式應用的角度看這一句的功能:

作者是要把這樣的顯示結果

. == (904724kb)

./bak == (1kb)

./billfile == (1kb)

./bin == (11646kb)

./bin/images == (16kb)

....................

替換成這樣的結果

|--bak (1kb)

|--billfile (1kb)

|--bin (11646kb)

| |--images (16kb)

對于"aaa/xxxx/yyyy =="分解這一要求,實際是兩步,先把"xxxx/yyyy =="替換為"|--yyyy",然後将aaa變成"| "(如沒有aaa則無行為),在aaa中含有幾個/,就換成幾個"| "。這裡的sed指令恰好完成了這一功能。

程式改進:

(1)實際該程式沒有使用ksh的任何特殊功能,改為sh仍可正常運作,相容性會更好。

(2)先find再du是沒有必要的。因為du本身就能尋找子目錄,且自動顯示每個子目錄的大小。另外,如果對指定的目錄無讀權限的話,find就會報出錯,但直接用du則沒事。

(3)"|"在sed中不是特殊字元不必再用"\"轉義了。

最後我的建議結果如下:

#!/bin/sh

du $dir| awk '{print $2, "== ("$1/2"kb)"}' |sort -f|sed -e "s,[^ /]*/\([^ /]*\) ==,|--\1," -e "s,[^ /]*/,| ,g"

作者: valentine    時間: 2002-3-21 23:27     标題: Shell的魅力

michaelds 解釋的太好了。

我想我們大家在注意shell的時候,應該注意shell中處處用得到的正規表達式。

^,$,.,*,[] 應該很清楚,這樣在sed ,awk,case,vi ...裡都能順暢自如.

繼續閱讀