一段檔案相關的shell指令碼解讀

2021-06-20 01:05:43 字數 2956 閱讀 9548

code:

#!/sbin/ksh

dir=$

(cd $dir;pwd)

find $dir -type d -print | du | awk '' |sort -f |

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

#the end

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

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

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

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

程式目的:

對指定的目錄,顯示該目錄及其下所有子目錄所占用的空間。顯示方式上,要求以類windows樹狀結構的方式表現目錄和子目錄的關係,顯示空間大小用(?kb)的樣式說明。

程式**:

(1)#!/sbin/ksh

(2)dir=$

(3)(cd $dir;pwd)

(4)find $dir -type d -print | du | awk '' |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)

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

替換成這樣的結果

. == (904724kb)

|--bak (1kb)

|--billfile (1kb)

|--bin (11646kb)

| |--images (16kb)

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

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

程式改進:

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

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

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

最後我的建議結果如下:

#!/bin/sh

dir=$

(cd $dir;pwd)

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

michaelds 解釋的太好了。

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

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

一段部署shell

一段部署shell usr bin env bash 目標伺服器ip host 1 目標伺服器端口 port 225 部署目錄 deploy dir 2 環境 env 3 備份目錄 bak dir deploy bak bak file api date y m d h m s tar.gz run...

一段SQL指令碼

create table gc col1 char 10 drop table gc 處理引數 declare str varchar 100 select str 1,2,3,4,5 插入處理 declare s varchar 8000 select s select replace str,u...

一段批處理指令碼 for 巢狀

1 伺服器上有一堆按日期生成的目錄,已經有n個月了,需要只取當前月份的目錄。2 目錄中有一系列檔案,檔案名字不一樣,但存在一定的重複規律。3 需要從伺服器上拷貝檔案到本地,自動去重,拷貝到本地。具體如下 r dir 驅動器 r 中的卷是 新加捲 卷的序列號是 3e8f 427a r 的目錄 驅動器 ...