一、sed命令介紹
我們都知道,vim采用的是交互式文本編輯模式,你可以用鍵盤命令來交互性地插入、刪除或替換數據中的文本。但sed命令則不同,它采用的是流編輯模式,最明顯的特點是,在sed命令處理數據之前,需要預先提供一組規則,sed命令會按照這個規則來編輯數據。
sed會根據腳本命令來處理文本文件中的數據,這些命令要么從命令行中輸入,要么存儲在一個文本文件中,此命令執行數據的順序如下:
- 每次僅讀取一行數據。
- 根據提供的規則命令匹配並修改數據。注意:sed默認不會直接修改源文件的數據,而是會將數據復制到緩沖區中,在緩沖區中修改數據。
- 將執行結果輸出。
當一行數據匹配完成后,它會繼續讀取下一行數據,並重復這個過程,直到將文件中所有數據處理完畢。
sed命令的基本格式如下:
sed [選項] [腳本命令] 文件名
該命令常用的選項及含義,如下表所示:
選項 | 含義 |
-e | 該選項會將其后跟的腳本命令添加到已有的命令中 |
-f | 該選項會將其后文件中的腳本命令添加到已有的命令中 |
-n | 默認情況下,sed 會在所有的腳本執行完畢后,會自動輸出處理后的內容,而該選項會屏蔽自動輸出,需使用 print 命令來完成輸出 |
-i | 此選項會直接修改源文件 |
成功使用 sed 命令的關鍵在於掌握各式各樣的腳本命令及格式,它能幫你定制編輯文件的規則。
二、sed腳本命令詳解
2.1、sed s替換腳本命令
此命令的基本格式為:
[address]s/pattern/replacement/flags
其中,address 表示指定要操作的具體行,pattern 指的是需要替換的內容,replacement 指的是要替換的新內容。關於指定具體操作行(address)的用法,這里先不做解釋,文章后續會對其做詳細介紹。此命令中常用的 flags 標記如下表所示:
flags標記 | 功能 |
n | 1~512 之間的數字,表示指定要替換的字符串出現第幾次時才進行替換,例如,一行中有 3 個 A,但用戶只想替換第二個 A,這時就用到這個標記 |
g | 對數據中所有匹配到的內容進行替換,如果沒有 g,則只會在第一次匹配成功時做替換操作。例如,一行數據中有 3 個 A,則只會替換第一個 A |
p | 會打印與替換命令中指定的模式匹配的行。此標記通常與 -n 選項一起使用 |
w file | 將緩沖區中的內容寫到指定的 file 文件中 |
& | 用正則表達式匹配的內容進行替換 |
\n | 匹配第 n 個子串,該子串之前在 pattern 中用 \(\) 指定 |
\ | 轉義(轉義替換部分包含:&、\ 等) |
比如,可以指定 sed 用新文本替換第幾處模式匹配的地方:
[root@localhost ~]# sed 's/test/trial/2' data.txt This is a test of the trial script. This is the second test of the trial script.
可以看到,使用數字 2 作為標記的結果就是,sed 編輯器只替換每行中第 2 次出現的匹配模式。
如果要用新文本替換所有匹配的字符串,可以使用 g 標記:
[root@localhost ~]# sed 's/test/trial/g' data.txt This is a trial of the trial script. This is the second trial of the trial script.
由上文可知,-n 選項會禁止 sed 輸出,但 p 標記會輸出修改過的行,將二者匹配使用的效果就是只輸出被替換命令修改過的行,例如:
[root@localhost ~]# cat data2.txt This is a test line. This is a different line. [root@localhost ~]# sed -n 's/test/trial/p' data2.txt This is a trial line.
w 標記會將匹配后的結果保存到指定文件中,比如:
[root@localhost ~]# sed 's/test/trial/w test.txt' data2.txt This is a trial line. This is a different line. [root@localhost ~]#cat test.txt This is a trial line.
在使用 s 腳本命令時,替換類似文件路徑的字符串會比較麻煩,需要將路徑中的正斜線進行轉義,例如:
[root@localhost ~]# sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd
2.2、sed d刪除腳本命令
此命令的基本格式為:
[address]d
如果需要刪除文本中的特定行,可以用 d 腳本命令,它會刪除指定行中的所有內容。但使用該命令時要特別小心,如果你忘記指定具體行的話,文件中的所有內容都會被刪除,舉個例子:
[root@localhost ~]# cat data1.txt The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog [root@localhost ~]# sed 'd' data1.txt #什么也不輸出,證明成了空文件(只是在緩沖區中刪除內容,並不會刪除源文件中的內容)
當和指定地址一起使用時,刪除命令顯然能發揮出大的作用。可以從數據流中刪除特定的文本行。例如:
- 通過行號指定,比如刪除 data6.txt 文件內容中的第 3 行:
[root@localhost ~]# cat data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. [root@localhost ~]# sed '3d' data6.txt This is line number 1. This is line number 2. This is line number 4.
- 或者通過特定行區間指定,比如刪除 data6.txt 文件內容中的第 2、3行:
[root@localhost ~]# sed '2,3d' data6.txt This is line number 1. This is line number 4.
- 也可以使用兩個文本模式來刪除某個區間內的行,但這么做時要小心,你指定的第一個模式會“打開”行刪除功能,第二個模式會“關閉”行刪除功能,因此,sed 會刪除兩個指定行之間的所有行(包括指定的行),例如:
[root@localhost ~]#sed '/1/,/3/d' data6.txt #刪除第 1~3 行的文本數據 This is line number 4.
- 或者通過特殊的文件結尾字符,比如刪除 data6.txt 文件內容中第 3 行開始的所有的內容:
[root@localhost ~]# sed '3,$d' data6.txt This is line number 1. This is line number 2.
在此強調,在默認情況下 sed 並不會修改原始文件,這里被刪除的行只是從 sed 的輸出中消失了,原始文件沒做任何改變。
2.3、sed a和i 添加腳本命令
a 命令表示在指定行的后面附加一行,i 命令表示在指定行的前面插入一行,這里之所以要同時介紹這 2 個腳本命令,因為它們的基本格式完全相同,如下所示:
[address]a(或 i)\新文本內容
下面分別就這 2 個命令,給讀者舉幾個例子。比如說,將一個新行插入到數據流第三行前,執行命令如下:
[root@localhost ~]# sed '3i\ > This is an inserted line.' data6.txt This is line number 1. This is line number 2. This is an inserted line. This is line number 3. This is line number 4.
再比如說,將一個新行附加到數據流中第三行后,執行命令如下:
[root@localhost ~]# sed '3a\ > This is an appended line.' data6.txt This is line number 1. This is line number 2. This is line number 3. This is an appended line. This is line number 4.
如果你想將一個多行數據添加到數據流中,只需對要插入或附加的文本中的每一行末尾(除最后一行)添加反斜線即可,例如:
[root@localhost ~]# sed '1i\ > This is one line of new text.\ > This is another line of new text.' data6.txt This is one line of new text. This is another line of new text. This is line number 1. This is line number 2. This is line number 3. This is line number 4.
可以看到,指定的兩行都會被添加到數據流中。
2.4、sed c 替換腳本命令
c 命令表示將指定行中的所有內容,替換成該選項后面的字符串。該命令的基本格式為:
[address]c\用於替換的新文本
舉個例子:
[root@localhost ~]# sed '3c\ > This is a changed line of text.' data6.txt This is line number 1. This is line number 2. This is a changed line of text. This is line number 4. # 在這個例子中,sed 編輯器會修改第三行中的文本,其實,下面的寫法也可以實現此目的: [root@localhost ~]# sed '/number 3/c\ > This is a changed line of text.' data6.txt This is line number 1. This is line number 2. This is a changed line of text. This is line number 4.
2.5、sed y 轉換腳本命令
y 轉換命令是唯一可以處理單個字符的 sed 腳本命令,其基本格式如下:
[address]y/inchars/outchars/
轉換命令會對 inchars 和 outchars 值進行一對一的映射,即 inchars 中的第一個字符會被轉換為 outchars 中的第一個字符,第二個字符會被轉換成 outchars 中的第二個字符...這個映射過程會一直持續到處理完指定字符。如果 inchars 和 outchars 的長度不同,則 sed 會產生一條錯誤消息。舉個簡單例子:
[root@localhost ~]# sed 'y/123/789/' data8.txt This is line number 7. This is line number 8. This is line number 9. This is line number 4. This is line number 7 again. This is yet another line. This is the last line in the file.
可以看到,inchars 模式中指定字符的每個實例都會被替換成 outchars 模式中相同位置的那個字符。 轉換命令是一個全局命令,也就是說,它會將文本行中找到的所有指定字符自動進行轉換,而不會考慮它們出現的位置,再打個比方:
[root@localhost ~]# echo "This 1 is a test of 1 try." | sed 'y/123/456/' This 4 is a test of 4 try.
sed 轉換了在文本行中匹配到的字符 '1' 的兩個實例,我們無法限定只轉換在特定地方出現的字符。
2.6、sed p 打印腳本命令
p 命令表示搜索匹配文本模式的行,並輸出該行的內容,此命令的基本格式為:
[address]p
p 命令常見的用法是打印包含匹配文本模式的行,例如:
[root@localhost ~]# cat data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. [root@localhost ~]# sed -n '/number 3/p' data6.txt This is line number 3.
可以看到,用 -n 選項和 p 命令配合使用,我們可以禁止輸出其他行,只打印包含匹配文本模式的行。 如果需要在修改之前查看行,也可以使用打印命令,比如與替換或修改命令一起使用。可以創建一個腳本在修改行之前顯示該行,如下所示:
[root@localhost ~]# sed -n '/3/{ > p > s/line/test/p > }' data6.txt This is line number 3. This is test number 3.
sed 命令會查找包含數字 3 的行,然后執行兩條命令。首先,腳本用 p 命令來打印出原始行;然后它用 s 命令替換文本,並用 p 標記打印出替換結果。輸出同時顯示了原來的行文本和新的行文本。
2.7、sed w 寫入文件腳本命令
w 命令用來將文本中指定行的內容寫入文件中,此命令的基本格式如下:
[address]w filename
這里的 filename 表示文件名,可以使用相對路徑或絕對路徑,但不管是哪種,運行 sed 命令的用戶都必須有文件的寫權限。 下面的例子是將數據流中的前兩行打印到一個文本文件中:
[root@localhost ~]# sed '1,2w test.txt' data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. [root@localhost ~]# cat test.txt This is line number 1. This is line number 2.
當然,如果不想讓行直接輸出,可以用 -n 選項,再舉個例子:
[root@localhost ~]# cat data11.txt Blum, R Browncoat McGuiness, A Alliance Bresnahan, C Browncoat Harken, C Alliance [root@localhost ~]# sed -n '/Browncoat/w Browncoats.txt' data11.txt [root@localhost ~]# cat Browncoats.txt Blum, R Browncoat Bresnahan, C Browncoat
可以看到,通過使用 w 腳本命令,sed 可以實現將包含文本模式的數據行寫入目標文件。
2.8、sed r 讀取文件腳本命令
r 命令用於將一個獨立文件的數據插入到當前數據流的指定位置,該命令的基本格式為:
[address]r filename
sed 命令會將 filename 文件中的內容插入到 address 指定行的后面,比如說:
[root@localhost ~]# cat data12.txt This is an added line. This is the second added line. [root@localhost ~]# sed '3r data12.txt' data6.txt This is line number 1. This is line number 2. This is line number 3. This is an added line. This is the second added line. This is line number 4.
如果你想將指定文件中的數據插入到數據流的末尾,可以使用 $ 地址符,例如:
[root@localhost ~]# sed '$r data12.txt' data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. This is an added line. This is the second added line.
2.9、sed q 退出腳本命令
q 命令的作用是使 sed 命令在第一次匹配任務結束后,退出 sed 程序,不再進行對后續數據的處理。 比如:
[root@localhost ~]# sed '2q' test.txt This is line number 1. This is line number 2.
可以看到,sed 命令在打印輸出第 2 行之后,就停止了,是 q 命令造成的,再比如:
[root@localhost ~]# sed '/number 1/{ s/number 1/number 0/;q; }' test.txt This is line number 0.
使用 q 命令之后,sed 命令會在匹配到 number 1 時,將其替換成 number 0,然后直接退出。
三、sed 腳本命令的尋址方式
前面在介紹各個腳本命令時,我們一直忽略了對 address 部分的介紹。對各個腳本命令來說,address 用來表明該腳本命令作用到文本中的具體行。默認情況下,sed 命令會作用於文本數據的所有行。如果只想將命令作用於特定行或某些行,則必須寫明 address 部分,表示的方法有以下 2 種:
1、以數字形式指定行區間;
2、用文本模式指定具體行區間。
以上兩種形式都可以使用如下這 2 種格式,分別是:
[address]腳本命令
或者
address {
多個腳本命令
}
以上兩種形式在前面例子中都有具體實例,因此這里不再做過多贅述。
3.1、以數字形式指定行區間
當使用數字方式的行尋址時,可以用行在文本流中的行位置來引用。sed 會將文本流中的第一行編號為 1,然后繼續按順序為接下來的行分配行號。在腳本命令中,指定的地址可以是單個行號,或是用起始行號、逗號以及結尾行號指定的一定區間范圍內的行。這里舉一個 sed 命令作用到指定行號的例子:
[root@localhost ~]#sed '2s/dog/cat/' data1.txt The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog
可以看到,sed 只修改地址指定的第二行的文本。下面的例子中使用了行地址區間:
[root@localhost ~]# sed '2,3s/dog/cat/' data1.txt The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy dog
在此基礎上,如果想將命令作用到文本中從某行開始的所有行,可以用特殊地址——美元符($):
[root@localhost ~]# sed '2,$s/dog/cat/' data1.txt The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy cat
3.2、用文本模式指定行區間
sed 允許指定文本模式來過濾出命令要作用的行,格式如下:
/pattern/command
注意,必須用正斜線將要指定的 pattern 封起來,sed 會將該命令作用到包含指定文本模式的行上。舉個例子,如果你想只修改用戶 demo 的默認 shell,可以使用 sed 命令,執行命令如下:
[root@localhost ~]# grep demo /etc/passwd demo:x:502:502::/home/Samantha:/bin/bash [root@localhost ~]# sed '/demo/s/bash/csh/' /etc/passwd root:x:0:0:root:/root:/bin/bash ... demo:x:502:502::/home/demo:/bin/csh ...
雖然使用固定文本模式能幫你過濾出特定的值,就跟上面這個用戶名的例子一樣,但其作用難免有限,因此,sed 允許在文本模式使用正則表達式指明作用的具體行。正則表達式允許創建高級文本模式匹配表達式來匹配各種數據。這些表達式結合了一系列通配符、特殊字符以及固定文本字符來生成能夠匹配幾乎任何形式文本的簡練模式。例如:
[root@localhost ~]# cat test.txt <html> <title>First Wed</title> <body> h1Helloh1 h2Helloh2 h3Helloh3 </body> </html> #使用正則表示式給所有第一個的h1、h2、h3添加<>,給第二個h1、h2、h3添加</> [root@localhost ~]# cat sed.sh /h[0-9]/{ s//\<&\>/1 s//\<\/&\>/2 } [root@localhost ~]# sed -f sed.sh test.txt <html> <title>First Wed</title> <body> <h1>Hello</h1> <h2>Hello</h2> <h3>Hello</h3> </body> </html>
解釋: 在上述命令中,"h[0-9]" 來匹配 h1、h2、h3,匹配到之后,把h前面的空白替換成<>,然后&表示將正則表達式匹配的內容(h1、h2、h3)替換到此處,最終的形式為<h1>、<h2>、<h3>,第二個替換命令原理也是這樣。
四、sed多行命令
在學習 sed 命令的基礎功能時,你可能注意到了一個局限,即所有的 sed 命令都只是針對單行數據執行操作,在 sed 命令讀取緩沖區中的文本數據時,它會基於換行符的位置,將數據分成行,sed 會根據定義好的腳本命令一次處理一行數據。 但是,有時我們需要對跨多行的數據執行特定操作。比如說,在文本中查找一串字符串"http://c.biancheng.net",它很有可能出現在兩行中,每行各包含其中一部分。這時,如果用普通的 sed 編輯器命令來處理文本,就不可能發現這種被分開的情況。 幸運的是,sed 命令的設計人員已經考慮到了這種情況,並設計了對應的解決方案。sed 包含了三個可用來處理多行文本的特殊命令,分別是:
1、Next 命令(N):將數據流中的下一行加進來創建一個多行組來處理。
2、Delete(D):刪除多行組中的一行。
3、Print(P):打印多行組中的一行。
注意,以上命令的縮寫,都為大寫。
4.1、N 多行操作命令
N 命令會將下一行文本內容添加到緩沖區已有數據之后(之間用換行符分隔),從而使前后兩個文本行同時位於緩沖區中,sed 命令會將這兩行數據當成一行來處理。 下面這個例子演示的 N 命令的功能:
[root@localhost ~]# cat data2.txt This is the header line. This is the first data line. This is the second data line. This is the last line. [root@localhost ~]# sed '/first/{ N ; s/\n/ / }' data2.txt This is the header line. This is the first data line. This is the second data line. This is the last line.
在這個例子中,sed 命令查找含有單詞 first 的那行文本,找到之后,會用N命令將下一行也放入緩沖區中(之間用換行符分隔),把兩行當成一行來處理,然后用替換命令s將換行符替換成空格。結果就是,文本文件中的兩行在sed的輸出中成了1行。如果要在數據文件中查找一個可能會分散在兩行中的文本短語,該如何實現呢?這里給大家一個實例:
[root@localhost ~]# cat data3.txt On Tuesday, the Linux System Administrator's group meeting will be held. All System Administrators should attend. Thank you for your attendance. [root@localhost ~]# sed 'N ; s/System Administrator/Desktop User/' data3.txt On Tuesday, the Linux Desktop User's group meeting will be held. All Desktop Users should attend. Thank you for your attendance.
用N命令將發現第一個單詞的那行和下一行在緩沖區合並后(之間用換行符分隔),即使短語內出現了換行,仍然可以找到它,這是因為,替換命令在 System 和 Administrator之間用了通配符(.)來匹配空格和換行符這兩種情況。但當它匹配了換行符時,它就從字符串中刪掉了換行符,導致兩行合並成一行。這可能不是你想要的。要解決這個問題,可以在 sed 腳本中用兩個替換命令,一個用來匹配短語出現在多行中的情況,一個用來匹配短語出現在單行中的情況,比如:
[root@localhost ~]# sed 'N > s/System\nAdministrator/Desktop\nUser/ > s/System Administrator/Desktop User/ > ' data3.txt On Tuesday, the Linux Desktop User's group meeting will be held. All Desktop Users should attend. Thank you for your attendance.
第一個替換命令專門查找類似這樣的短語:'System\nAdministrator',即‘System’和‘Administrator’不在同一行的情況,並用‘Desktop\nUser’來替換。這樣就可以做到:找到跨行的短語並用跨行的短語來替換。所以輸出的時候,‘Desktop’和‘User’仍在兩行中。
但這個腳本中仍有個小問題,即它總是在執行 sed 命令前將下一行文本讀入到緩沖區中,當它到了最后一行文本時,就沒有下一行可讀了,此時 N 命令會叫 sed 程序停止,這就導致,如果要匹配的文本正好在最后一行中,sed 命令將不會發現要匹配的數據。解決這個問題的方法是,將單行命令放到 N 命令前面,將多行命令放到 N 命令后面,像這樣:
[root@localhost ~]# sed ' > s/System\nAdministrator/Desktop\nUser/ > N > s/System Administrator/Desktop User/ > ' data3.txt On Tuesday, the Linux Desktop User's group meeting will be held. All Desktop Users should attend. Thank you for your attendance.
現在,查找單行中短語的替換命令在數據流的后一行也能正常工作,多行替換命令則會負責短語出現在數據流中間的情況。
4.2、D 多行刪除命令
sed 不僅提供了單行刪除命令(d),也提供了多行刪除命令 D,其作用是只刪除緩沖區中的第一行,也就是說,D 命令將緩沖區中第一個換行符(包括換行符)之前的內容刪除掉。例如:
[root@localhost ~]# cat data4.txt On Tuesday, the Linux System Administrator's group meeting will be held. All System Administrators should attend. [root@localhost ~]# sed 'N ; /System\nAdministrator/D' data4.txt Administrator's group meeting will be held. All System Administrators should attend.
文本的第二行被 N 命令加到了緩沖區,因此 sed 命令第一次匹配就是成功,而 D 命令會將緩沖區中第一個換行符之前(也就是第一行)的數據刪除,所以,得到了如上所示的結果。 下面的例子中,它會刪除數據流中出現在第一行前的空白行:
[root@localhost ~]# cat data5.txt This is the header line. This is a data line. This is the last line. [root@localhost ~]# sed '/^$/{N ; /header/D}' data5.txt This is the header line. This is a data line. This is the last line.
sed會查找空白行,然后用 N 命令來將下一文本行添加到緩沖區。此時如果緩沖區的內容中含有單詞 header,則 D 命令會刪除緩沖區中的第一行,即第一個換行符(包括換行符)之前的內容。
4.3、P 多行打印命令
同 d 和 D 之間的區別一樣,P(大寫)命令和單行打印命令 p(小寫)不同,對於具有多行數據的緩沖區來說,它只會打印緩沖區中的第一行,也就是首個換行符之前的所有內容。例如,test.txt 文件中的內容如下:
[root@localhost ~]# cat test.txt aaa bbb ccc ddd eee fff
下表是對 test.txt 文件中的內容分別用 p 命令和 P 命令后,產生的輸出信息的對比。
第一個 sed 命令,每次都使用 N 將下一行內容追加到緩沖區內容的后面(用換行符間隔),也就是說,第一次執行命令時緩沖區中的內容為 aaa\nbbb,但 P(大寫) 命令的作用是打印換行符之前的內容,也就是 aaa,之后執行的是 sed 的自動輸出功能,輸出 aaa 和 bbb(sed 命令會自動將 \n 輸出為換行),依次類推,就輸出了所看到的結果。第二個 sed 命令,使用的是 p (小寫)單行打印命令,它會將緩沖區中的所有內容全部打印出來(\n 會自動輸出為換行),因此,就會出現上述結果。
五、sed保持空間
前面我們一直說,sed 命令處理的是緩沖區中的內容,其實這里的緩沖區,應稱為模式空間。值得一提的是,模式空間並不是 sed 命令保存文件的唯一空間。sed 還有另一塊稱為保持空間的緩沖區域,它可以用來臨時存儲一些數據。下表列出了 5 條可用來操作保持空間的命令。
命令 | 功能 |
h | 將模式空間中的內容復制到保持空間 |
H | 將模式空間中的內容附加到保持空間 |
g | 將保持空間中的內容復制到模式空間 |
G | 將保持空間中的內容附加到模式空間 |
x | 交換模式空間和保持空間中的內容 |
通常,在使用 h 或 H 命令將字符串移動到保持空間后,最終還要用 g、G 或 x 命令將保存的字符串移回模式空間。保持空間最直接的作用是,一旦我們將模式空間中所有的文件復制到保持空間中,就可以清空模式空間來加載其他要處理的文本內容。由於有兩個緩沖區域,下面的例子中演示了如何用 h 和 g 命令來將數據在 sed 緩沖區之間移動。
[root@localhost ~]# cat data2.txt This is the header line. This is the first data line. This is the second data line. This is the last line. [root@localhost ~]# sed -n '/first/{h;p;n;p;g;p;}' data2.txt This is the first data line. This is the second data line. This is the first data line.
這個例子的運行過程是這樣的:
- sed腳本命令用正則表達式過濾出含有單詞first的行;
- 當含有單詞 first 的行出現時,h 命令將該行放到保持空間;
- p 命令打印模式空間也就是第一個數據行的內容;
- n 命令提取數據流中的下一行(This is the second data line),並將它放到模式空間;
- p 命令打印模式空間的內容,現在是第二個數據行;
- g 命令將保持空間的內容(This is the first data line)放回模式空間,替換當前文本;
- p 命令打印模式空間的當前內容,現在變回第一個數據行了。
六、sed改變指定流程
6.1、b分支命令
通常,sed 程序的執行過程會從第一個腳本命令開始,一直執行到最后一個腳本命令(D 命令是個例外,它會強制 sed 返回到腳本的頂部,而不讀取新的行)。sed 提供了 b 分支命令來改變命令腳本的執行流程,其結果與結構化編程類似。b 分支命令基本格式為:
[address]b [label]
其中,address 參數決定了哪些行的數據會觸發分支命令,label 參數定義了要跳轉到的位置。需要注意的是,如果沒有加 label 參數,跳轉命令會跳轉到腳本的結尾,比如:
[root@localhost ~]# cat data2.txt This is the header line. This is the first data line. This is the second data line. This is the last line. [root@localhost ~]# sed '{2,3b ; s/This is/Is this/ ; s/line./test?/}' data2.txt Is this the header test? This is the first data line. This is the second data line. Is this the last test?
可以看到,因為 b 命令未指定 label 參數,因此數據流中的第2行和第3行並沒有執行那兩個替換命令。如果我們不想直接跳到腳本的結尾,可以為 b 命令指定一個標簽(也就是格式中的 label,最多為 7 個字符長度)。在使用此該標簽時,要以冒號開始(比如 :label2),並將其放到要跳過的腳本命令之后。這樣,當 sed 命令匹配並處理該行文本時,會跳過標簽之前所有的腳本命令,但會執行標簽之后的腳本命令。比如說:
[root@localhost ~]# sed '{/first/b jump1 ; s/This is the/No jump on/ > :jump1 > s/This is the/Jump here on/}' data2.txt No jump on header line Jump here on first data line No jump on second data line No jump on last line
在這個例子中,如果文本行中出現了 first,程序的執行會直接跳到 jump1 標簽之后的腳本行。如果分支命令的模式沒有匹配,sed 會繼續執行所有的腳本命令。b 分支命令除了可以向后跳轉,還可以向前跳轉,例如:
[root@localhost ~]# echo "This, is, a, test, to, remove, commas." | sed -n '{ > :start > s/,//1p > /,/b start > }' This is, a, test, to, remove, commas. This is a, test, to, remove, commas. This is a test, to, remove, commas. This is a test to, remove, commas. This is a test to remove, commas. This is a test to remove commas.
在這個例子中,當緩沖區中的行內容中有逗號時,腳本命令就會一直循環執行,每次迭代都會刪除文本中的第一個逗號,並打印字符串,直至內容中沒有逗號。
6.2、t測試命令
類似於 b 分支命令,t 命令也可以用來改變 sed 腳本的執行流程。t 測試命令會根據 s 替換命令的結果,如果匹配並替換成功,則腳本的執行會跳轉到指定的標簽;反之,t 命令無效。測試命令使用與分支命令相同的格式:
[address]t [label]
跟分支命令一樣,在沒有指定標簽的情況下,如果 s 命令替換成功,sed 會跳轉到腳本的結尾(相當於不執行任何腳本命令)。例如:
[root@localhost ~]# sed '{ > s/first/matched/ > t > s/This is the/No match on/ > }' data2.txt No match on header line This is the matched data line No match on second data line No match on last line
此例中,第一個替換命令會查找模式文本 first,如果匹配並替換成功,命令會直接跳過后面的替換命令;反之,如果第一個替換命令未能匹配成功,第二個替換命令就會被執行。再舉個例子:
[root@localhost ~]# echo "This, is, a, test, to, remove, commas. " | sed -n '{ > :start > s/,//1p > t start > }' This is, a, test, to, remove, commas. This is a, test, to, remove, commas. This is a test, to, remove, commas. This is a test to, remove, commas. This is a test to remove, commas. This is a test to remove commas.
在上面的例子中,sed會先對文本執行s替換操作,即把每行的第1個逗號(,)替換成空字符並打印本行。如果替換操作成功,則會執行t命令的start標簽中的命令,即繼續替換逗號,直到文本中沒有逗號為止。