sed意為流編輯器(Stream Editor),在Shell腳本和Makefile中作為過濾器使用非常普遍,也就是把前一個程序的輸出引入sed的輸入,經過一系列編輯命令轉換為另一種格式輸出。sed和vi都源於早期UNIX的ed工具,所以很多sed命令和vi的末行命令是相同的。
sed命令行的基本格式為
sed option 'script' file1 file2 ... sed option -f scriptfile file1 file2 ...
sed處理的檔案既可以由標準輸入重定向得到,也可以當命令行參數傳入,命令行參數可以一次傳入多個檔案,sed會依次處理。sed的編輯命令可以直接當命令行參數傳入,也可以寫成一個腳本檔案然後用-f參數指定,編輯命令的格式為
/pattern/action
其中pattern是正則表達式,action是編輯操作。sed程序一行一行讀出待處理檔案,如果某一行與pattern匹配,則執行相應的action,如果一條命令沒有pattern而只有action,這個action將作用於待處理檔案的每一行。
表 32.5. 常用的sed命令
/pattern/p | 打印匹配pattern的行 |
/pattern/d | 刪除匹配pattern的行 |
/pattern/s/pattern1/pattern2/ | 查找符合pattern的行,將該行第一個匹配pattern1的字元串替換為pattern2 |
/pattern/s/pattern1/pattern2/g | 查找符合pattern的行,將該行所有匹配pattern1的字元串替換為pattern2 |
使用p命令需要注意,sed是把待處理檔案的內容連同處理結果一起輸出到標準輸出的,因此p命令表示除了把檔案內容打印出來之外還額外打印一遍匹配pattern的行。比如一個檔案testfile的內容是
123 abc 456
打印其中包含abc的行
$ sed '/abc/p' testfile 123 abc abc 456
要想只輸出處理結果,應加上-n選項,這種用法相當於grep命令
$ sed -n '/abc/p' testfile abc
使用d命令就不需要-n參數了,比如刪除含有abc的行
$ sed '/abc/d' testfile 123 456
注意,sed命令不會修改原檔案,刪除命令只表示某些行不打印輸出,而不是從原檔案中刪去。
使用查找替換命令時,可以把匹配pattern1的字元串複製到pattern2中,比如:
$ sed 's/bc/-&-/' testfile 123 a-bc- 456
pattern2中的&表示原檔案的當前行中與pattern1相匹配的字元串,再比如:
$ sed 's/\([0-9]\)\([0-9]\)/-\1-~\2~/' testfile -1-~2~3 abc -4-~5~6
pattern2中的\1表示與pattern1的第一個()括號相匹配的內容,\2表示與pattern1的第二個()括號相匹配的內容。sed預設使用Basic正則表達式規範,如果指定了-r選項則使用Extended規範,那麼()括號就不必轉義了。
如果testfile的內容是
<html><head><title>Hello World</title> <body>Welcome to the world of regexp!</body></html>
現在要去掉所有的HTML標籤,使輸出結果為
Hello World Welcome to the world of regexp!
怎麼做呢?如果用下面的命令
$ sed 's/<.*>//g' testfile
結果是兩個空行,把所有字元都過濾掉了。這是因為,正則表達式中的數量限定符會匹配儘可能長的字元串,這稱為貪心的(Greedy)[39]。比如sed在處理第一行時,<.*>匹配的並不是<html>或<head>這樣的標籤,而是
<html><head><title>Hello World</title>
這樣一整行,因為這一行開頭是<,中間是若干個任意字元,末尾是>。那麼這條命令怎麼改才對呢?留給讀者思考。