sed處理文本的方法
sed在處理文本時,會先讀取第一個輸入行,將編輯命令應用於輸入行,然後讀取下一個輸入行,並應用編輯命令。sed總是處理最新版本的行,因此sed中有多個編輯命令時,編輯命令的順序對結果會有影響,下一個編輯命令會發生了變化的行而不是原始行,如示例:
[root@fanyue sed]# cat test This is a pig. This is a cow. [root@fanyue sed]# sed 's/pig/cow/; s/cow/horse/' test This is a horse. This is a horse.
可以看到sed中第二個編輯命令處理的行是被第一個命令處理之後的內容。
模式空間
sed維護一種模式空間,即一個工作區或者臨時緩沖區,當使用編輯命令時將在模式空間中存儲單個輸入行。一次一行的設計的有點是在讀取非常龐大的文件時不會出現內存溢出或緩慢的問題。
初始時,模式空間包含有單個輸入行的備份。然後按照命令順序對模式空間的中的行進行處理。當應用了所有的指令後,當前行被輸出,下一行被讀入模式空間。然後腳本中的指令再次按順序應用於新的行。即sed的處理步驟為:
生成輸入行的備份到模式空間中
修改模式空間的中的備份
將修改後的備份輸出到標准輸出
回到上面的示例,如果我想將pig改為cow, cow改為horse改如何處理?
[root@fanyue sed]# sed 's/cow/horse/; s/pig/cow/' test
1 This is a cow.
2 This is a horse.
將命令的順序反轉即可!
sed還維護了一個稱為保持空間(hold space)的另一個臨時緩沖區,保持空間可以將模式空間的內容復制到保持空間並在以後檢索它們。
sed的尋址
默認情況下,sed將命令用於每一個行。sed命令可以指定0個,1個或2個地址。每個地址都是一個描述模式、行號或者行尋址符號的正則表達式。
如果沒有指定地址,那麼命令將應用於每一行。
如果只有一個地址,那麼命令應用於與這個地址匹配的任意行。
如果指定了由逗號分隔的兩個地址,那麼命令將應用於匹配第一個地址的第一行和它後面的行,直到匹配第二個地址的行(包括此行)。
如果地址後面跟有感歎號(!),那麼命令就應該用於不匹配該地址的所有行。
例如,d命令代表刪除匹配的行,一個d命令會刪除所有的行,不會有任何輸出,如:
[root@fanyue sed]# cat test
1 This is a pig.
2 This is a cow.
3 This is a dog.
4 And this is a monkey!!!
[root@fanyue sed]# sed 'd' test
當行號所有地址提供時,則命令只會刪除匹配的那一行。例如,下面的示例只會刪除第一行:
[root@fanyue sed]# sed '1d' test
2 This is a cow.
3 This is a dog.
4 And this is a monkey!!!
行號指由sed維護的內部行數。該計數器不會因為多個輸入文件而重置。因此,不管指定多少個輸入文件,1只代表輸入流的第一行,如果輸入流是多個文件,那麼1代表第一個輸入文件的第一行。
同樣輸入流也只有一個最後的行。可以使用尋址符號$指定。下面的示例刪除輸入的最後一行:
[root@fanyue sed]# sed '$d' test
1 This is a pig.
2 This is a cow.
3 This is a dog.
$符號不要和正則表達式中的$混淆,在正則表達式作為地址提供時,這個命令只影響與這個模式匹配的行。正則表達式必須封閉在斜槓(/)中。下面的刪除命令:
[root@fanyue sed]# sed '/!$/d' test
1 This is a pig.
2 This is a cow.
3 This is a dog.
只刪除以!結尾的行。
如果提供兩個地址,那麼就指定了命令執行的范圍。下面的示例展示了刪除兩個地址之間的所有行,兩個地址以逗號隔開:
[root@fanyue sed]# sed '/cow/,/monkey/d' test
1 This is a pig.
它刪除從一個模式匹配開始,到由第二種模式匹配的行(包括此行在內)為止的所有行。下面的命令刪除了文件中從5行到最後一行的所有行:
[root@fanyue sed]# sed '5,$d' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
可以混合使用行地址和模式地址:
1,/^$/d
本欄目更多精彩內容:http://www.bianceng.cn/OS/Linux/
sed沒有辦法先行判斷第二個地址是否存在匹配的行,因此當命令執行後sed會從一個匹配的行開始應用命令,如果沒有出現第二個匹配的行,那麼將刪除所有的行。
跟在地址後面的感歎號會反轉匹配的意義:
[root@fanyue sed]# sed '1,2!d' test
1 This is a pig.
2 This is a cow.
sed使用大括號({})將一個地址嵌套在另一個地址中,或者在相同的地址上應用多個命令。如果想指定行的范圍,然後在這個范圍內指定另一個地址,則可以嵌套地址。例如:
[root@fanyue sed]# cat test This is a pig. ------------- This is a cow. ------------- this is a cat. ------------- This is a dog. ------------- And this is a monkey!!! [root@fanyue sed]# sed '/cow/,/dog/ {/^$/d; s/-/*/g}' test This is a pig. ------------- This is a cow. ************* this is a cat. ************* This is a dog. ------------- And this is a monkey!!!