「三劍客」之sed手中有劍

一、sed介紹

  sed是Stream Editor(字符流編輯器)的縮寫,簡稱流編輯器。sed是操作、過濾和轉換文本內容的強大工具。常用功能包括對文件實現快速增刪改查(增加、刪除、修改、查詢),其中查詢的功能中最常用的兩大功能是過濾(過濾指定字符串)、取行(取出指定行)

  sed通過執行下面的循環來操作輸入流中的每一行: 首先,sed讀取輸入流中的一行,移除該行的尾隨換行符,並將其放入到pattern space中。然後對pattern space中的內容執行SCRIPT中的sed命令,每個sed命令都可以關聯一個地址:地址是一種條件判斷代碼,只有符合條件的行才會執行相應的命令。當執行到SCRIPT(指的是我們定義的操作)的尾部時,除非指定了”-n”選項,否則pattern space中的內容將寫到標準輸出流中,並添加回尾隨的換行符。然後進入下一個循環開始處理輸入流中的下一行。

  但有些特殊命令(如”D”命令)會進入多行模式,使得SCRIPT循環結束 時將數據鎖在pattern space中不輸出也不清空,甚至在SCRIPT循環還沒結束時就強行進入下一 輪SCRIPT循環,其實就相當 於在上面的while循環結構中加上了”continue”關鍵字。此外還有命令(如”d”)可以直接退出 SCRIPT循環進入下一個sed循環,就像是在while循環中加上了”break”一樣。甚至還有直接退出 sed循環的命令(只有2個這樣的命令:”q”和”Q”),就像是加上了”exit”一樣。

sed的執行過程是一個循環的過程:

  1. 讀取輸入流的一行到模式空間。
  2. 對模式空間中的內容進行匹配和處理。(這裡一般都是我們進行操作的地方,增刪改查等)
  3. 自動輸出模式空間內容。
  4. 清空模式空間內容。

二、基本選項

命令格式:

sed的命令格式:sed [options] 'command' file(s);
sed的腳本格式:sed [options] -f scriptfile file(s);

基本選項如下:

-e :直接在命令行模式上進行sed動作編輯,此為默認選項;
-f :將sed的動作寫在一個文件內,用–f filename 執行filename內的sed動作;
-i :直接修改文件內容,sed是通過創建一個臨時文件並將輸入寫入到該臨時文件,然後重命名為源文件來實現的
-n :只打印模式匹配的行;
-r :支持擴展表達式,sed所支持的擴展正則表達式和egrep一樣
-s : 考慮為多個單獨的文件,而不是把多個文件作為一個流進行輸入
-h或--help:顯示幫助;
-V或--version:顯示版本信息。

實例練習:首先我們準備文件test.txt,內容如下

1、Last weekend, I was busy。 
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。
[root@lgh test]# sed  -n '3p' test.txt  #打印第三行
3、I did my homework and watched TV。 On Sunday morning ,
[root@lgh test]# sed  '=' test.txt  #打印行號
1
1、Last weekend, I was busy。
2
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3
3、I did my homework and watched TV。 On Sunday morning ,
4
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5
5、It was fun 。I had a very happy weekend。
[root@lgh test]# sed  -r -n '/[a-z]*ing/p' test.txt  #正則匹配ing字符串
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,

三、定址選擇

這裡所說的地址選擇就是我們要處理一個文檔中的哪些行?比如第1行到第3行,這就是用來選擇匹配我們需要進行處理的行。

當sed將輸入流中的行讀取到模式空間後,就需要對模式空間中的內容進行匹配,如果能匹配就能執行對應的命令,如果不能匹配就直接輸出、清空模式空間並進入下一個sed循環讀取下一行。
定址表達式有多種,其格式為[ADDR1][,ADDR2]。這可以分為3種方式:

  • ADDR1和ADDR2都省略時,表示所有行都能被匹配上。
  • 省略ADDR2時,表示只有被ADDR1表達式匹配上的行才符合條件。
  • 不省略ADDR2時,是範圍地址。表示從ADDR1匹配成功的行開始,到ADDR2匹配成功的行結束。

‘NUMBER’:指定一個行號,sed將僅只匹配該行。(需要注意,除非使用了”-s”或”-i”選項,sed將對所有輸入文件的行連續計數。)
‘FIRST~STEP’:FIRST和STEP都是非負數。該定址表達式表示從第FIRST行開始,每隔STEP行就再取一次。要選擇所有的奇數行,使用「1~2」;
‘$’:該符號匹配的是最後一個文件的最後一行,如果指定了”-i”或”-s”,則匹配的是每個文件的最後一行。
‘/REGEXP/‘:該定址表達式將選擇那些能被正則表達式REGEXP匹配的所有行。如果REGEXP中自身包含了字符”/”,則必須使用反斜線進行轉義,即”\/”。
‘/REGEXP/I’:正則表達式的修飾符”I”是GNU的擴展功能,表示REGEXP在匹配時不區分大小寫。
‘/REGEXP/M’:可以讓sed直接匹配多行模式下(multi-line mode)的位置。該修飾符使得正則表達式的元字符”^”和”$”匹配分別匹配每個新行後的空字符和新行前的空字符。還有另外兩個特殊的字符序列(\`和\’,分別是反斜線加反引號,反斜線加單引號),它們總是匹配buffer空間中的起始和結束位置。此外,元字符點”.”不能匹配多行模式下的換行符。
(註:在單行模式下,使用M和不使用M是沒有區別的,但在多行模式下各符號匹配的位置將和通常的正則表達式元字符匹配的內容不同,各符號的匹配位置如下圖所示)
‘0,/REGEXP/’:使用行號0作為起始地址也是支持的,就像此處的”0,/REGEXP/”,這時sed會嘗試對第一行就匹配REGEXP。換句話說,”0,/REGEXP/”和”1,/REGEXP/”基本是相同的。但以行號0作為起始行時,如果第一行就能被ADDR2匹配,範圍搜索立即就結束,因為第二個地址已經搜索到了;如果以行號1作為起始行,會從第二行開始匹配ADDR2,直到匹配成功。
‘ADDR1,+N’:匹配ADDR1和其後的N行。
‘ADDR1,~N’:匹配ADDR1和其後的行直到出現N的倍數行,倍數可為隨意整數倍。 (註:可以是任意倍,只要N的倍數是最接近且大於ADDR1的即可。如ADDR1=1,N=3匹配1到3行,ADDR1=5,N=4匹配5-8行。

注意:sed採用計數器計算,每讀取一行,計數器加1,直到最後一行。因此在讀到最後一行前,sed是不知道這次輸入流中總共有多上行,也不知道最後一行是第幾行。”$”符號表示最後一行,它只是一個特殊的標識符號。當sed讀取到輸入流的尾部時,sed就會為該行打上該標記。無法使用”$”參與數學運算,例如無法使用$-1表示倒數第二行,因為sed在讀到最後一行前,它並不知道這是倒數第二行,此時也還沒打”$”標記,因此$-1是錯誤的定址表達式。另一方面,sed只能通過一次輸入流,這意味着已經讀取過的行無法再次被讀取,所以sed不提供往回取數據的定址表達式

常用的正則匹配模式:

^ 匹配行開始,如:/^sed/匹配所有以sed開頭的行;
 $ 匹配行結束,如:/sed$/匹配所有以sed結尾的行;
 . 匹配一個非換行符的任意字符,如:/s.d/匹配s後接一個任意字符,最後是d;
 * 匹配0個或多個字符,如:/*sed/匹配所有模板是一個或多個空格後緊跟sed的行;
 [] 匹配一個指定範圍內的字符,如/[ss]ed/匹配sed和Sed;
 [^] 匹配一個不在指定範圍內的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一個字母開頭,緊跟ed的行;
 \(..\) 匹配子串,保存匹配的字符,如s/\(love\)able/\1rs,loveable被替換成lovers;
 & 保存搜索字符用來替換其他字符,如s/love/**&**/,love這成**love**;
 \< 匹配單詞的開始,如:/\ 
 \> 匹配單詞的結束,如/love\>/匹配包含以love結尾的單詞的行;
 x\{m\} 重複字符x,m次,如:/0\{5\}/匹配包含5個0的行;
 x\{m,\} 重複字符x,至少m次,如:/0\{5,\}/匹配至少有5個0的行;
 x\{m,n\} 重複字符x,至少m次,不多於n次,如:/0\{5,10\}/匹配5~10個0的行;

實例 :

[root@lgh test]# sed -n 1,3p test.txt #輸出1-3行
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
[root@lgh test]# sed -n 1p test.txt #輸出第一行
1、Last weekend, I was busy。
[root@lgh test]# sed -n 1,/On/p test.txt #輸出第一行到匹配到On字符串的行
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
[root@lgh test]# sed -n 1,/[a-z]*ing/p test.txt #輸出第一行到匹配到ing字符串的行
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
[root@lgh test]# sed -r -n 1,/[a-z]*ing/p test.txt
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
[root@lgh test]# sed -r -n 1,+2p test.txt #輸出從第一行開始以及後兩行
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
[root@lgh test]# sed -n 1,~2p test.txt #從第一行開始輸出到2的倍數行
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
[root@lgh test]# sed -n 3,~2p test.txt #從第3行開始輸出到2的倍數行
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
[root@lgh test]# sed -n 1~2p test.txt #輸出從第一行開始,步長為的2的行
1、Last weekend, I was busy。
3、I did my homework and watched TV。 On Sunday morning ,
5、It was fun 。I had a very happy weekend。
[root@lgh test]# sed -n /on/I,/with/Ip test.txt #輸出匹配on到with的行,忽略大小寫
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。

我們知道匹配到我們需要操作的行的時候,開始進行我們需要的操作,請繼續看下文

四、常用命令

常用命令如下:

a 在當前行下面插入文本;
i 在當前行上面插入文本;
c 把選定的行改為新的文本;
d 刪除,刪除選擇的行;
D 刪除模板塊的第一行;
s 替換指定字符;
h 拷貝模板塊的內容到內存中的緩衝區;
H 追加模板塊的內容到內存中的緩衝區;
g 獲得內存緩衝區的內容,並替代當前模板塊中的文本;
G 獲得內存緩衝區的內容,並追加到當前模板塊文本的後面;
l 列表不能打印字符的清單;
n 讀取下一個輸入行,用下一個命令處理新的行而不是用第一個命令;
N 追加下一個輸入行到模板塊後面並在二者間嵌入一個新行,改變當前行號碼;
p 打印模板塊的行。 P(大寫) 打印模板塊的第一行;
q 退出Sed;
b lable 分支到腳本中帶有標記的地方,如果分支不存在則分支到腳本的末尾;
r file 從file中讀行;
t label if分支,從最後一行開始,條件一旦滿足或者T,t命令,將導致分支到帶有標號的命令處,或者到腳本的末尾;
T label 錯誤分支,從最後一行開始,一旦發生錯誤或者T,t命令,將導致分支到帶有標號的命令處,或者到腳本的末尾;
w file 寫並追加模板塊到file末尾;
W file 寫並追加模板塊的第一行到file末尾;
! 表示後面的命令對所有沒有被選定的行發生作用;
= 打印當前行號;
# 把注釋擴展到下一個換行符以前;

 1、強制輸出命令p

默認情況下sed會輸出所有的行,使用-n可以禁用默認的輸出,然後使用p指定自己想輸出的行。

[root@lgh test]# sed 1,2p test.txt  #沒事使用-n,所以1,2行重複答應,兩種輸出模式不衝突
1、Last weekend, I was busy。
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。
[root@lghtest]# sed -n 1,2p test.txt  #輸出1,2行
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,

2、刪除命令d

命令”d”用於刪除整個模式空間中的內容,並立即退出當前SCRIPT循環,進入下一個sed循環,即讀取下一行 

[root@lgh test]# sed 3,5d test.txt  #刪除第3行到第5行的數據
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,

修改test.txt內容如下:

#!/bin/bash
#test
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。
[root@lghtest]# sed '/^#/{1!d}' test.txt #刪除以#開頭的行,第一行例外
#!/bin/bash
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。

如果”d”後面還有命令,在刪除模式空間後,這些命令不會執行,因為會立即退出當前SCRIPT循環

3、退出命令q或者Q

“q”和”Q”命令的作用是立即退出當前sed程序,使其不再執行後面的命令,也不再讀取後面的行。因此,在處理大文件或大量文件時,使用”q”或”Q”命令能提高很大效率。它們之間的不同之處在於”q”命令被執行後還會使用自動輸出動作輸出模式空間的內容,除非使用了”-n”選項。而”Q”命令則會立即退出,不會輸出模式空間內容。另外,可以為它們指定退出狀態碼,例如”q 1″

[root@lgh test]# sed '3q' test.txt #輸出錢3行,類似 head -3
#!/bin/bash
#test
1、Last weekend, I was busy。
[root@lgh test]# sed -n '/[a-z]*ing/{p;q}' test.txt #找到一條ing的字符串,輸出並退出
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,

4、輸出行號=

“=”命令用於輸出最近被讀取行的行號。在sed內部,使用行號計數器進行行號計數,每讀取一行,行號計數器加1。

[root@lgh test]# sed -n '/[a-z]*ing/{p;=;q}' test.txt #找到一條ing的字符串,輸出行並輸出行號,然後退出
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
4

5、字符一一對應替換命令”y”

該命令和”tr”命令的映射功能一樣,都是將字符進行一一替換

[root@lghtest]# sed 'y/ing/ING/' test.txt #把文檔中的ing一一對應替換成ING
#!/bIN/bash
#test
1、Last weekeNd, I was busy。
2、ON Saturday morNING, my classmate aNd I had Math traINING class。 Saturday afterNooN,
3、I dId my homework aNd watched TV。 ON SuNday morNING4、I weNt to HaNG zhou MeteorolGIcal ExperIeNce Hall wIth my famIly。
5、It was fuN 。I had a very happy weekeNd。

6、讀取下一行命令”n”

在sed的循環過程中,每個sed循環的第一步都是讀取輸入流的下一行到模式空間中,這是我們無法控制的動作。但sed有讀取下一行的命令”n”。

[root@lgh test]# sed -n '/[a-z]*ing/{p;n;p}' test.txt #輸出匹配到ing字符串的一行和下一行
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
[root@lgh test]# sed -n '/[a-z]*ing/{p;n;n;p}' test.txt #輸出匹配到ing字符串的一行和下下行
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。

7、替換命令s

命令格式:s/REGEXP/REPLACEMENT/FLAGS

功能就是替換,首先需要匹配,然後再替換,常用的選項如下:

g 表示行內全面替換;
p 表示打印行;
\1 子串匹配標記;
& 已匹配字符串標記;

修改test.txt的內容如下:

#!/bin/bash
#test test1 test2 test3
#test4 test5 test6 test7
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。
[root@lgh test]# sed -n 's/test/TEST/p' test.txt #替換並打印,默認替換第一列
#TEST test1 test2 test3
#TEST4 test5 test6 test7
[root@lgh test]# sed -n 's/test/TEST/gp' test.txt #全局替換
#TEST TEST1 TEST2 TEST3
#TEST4 TEST5 TEST6 TEST7
[root@lgh test]# sed -n 's/test/TEST/2p' test.txt #指定列替換
#test TEST1 test2 test3
#test4 TEST5 test6 test7
[root@lgh test]# sed -n '5,$s/ing/***&***/p' test.txt #給匹配到的字符串添加*
2、On Saturday morn***ing***, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morn***ing*** ,
[root@lgh test]# sed -n '5,$s/^/#/p' test.txt #在第5行到最後一行添加註釋
#2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
#3、I did my homework and watched TV。 On Sunday morning ,
#4、I went to Hang zhou Meteorolgical Experience Hall with my family。
#5、It was fun 。I had a very happy weekend。
[root@mvxl2685 test]# echo 'cmd1 && cmd2 || cmd3' | sed 's%&&\(.*\)||\(.*\)%\&\&\2||\1%' #cmd1 && cmd2 || cmd3"的cmd2和cmd3命令對調個位置
cmd1 && cmd3|| cmd2

8、追加(a)、插入(i)、修改(c)

三種格式是”[a|i|c] TEXT”,表示將TEXT內容隊列化到內存中,當有輸出流或者說有輸出動作的時候,半路追上輸出流,分別追加、插入和替換到該輸出流然後輸出。追加是指追加在輸出流的尾部,插入是指插入在輸出流的首部,替換是指將整個輸出流替換掉。”c”命令和”a”、”i”命令有一絲不同,它替換結束後立即退出當前SCRIPT循環,並進入下一個sed循環,因此”c”命令後的命令都不會被執行。

[root@mvxl2685 test]# sed '/ing/a good job' test.txt #在匹配行後面追加
#!/bin/bash
#test test1 test2 test3
#test4 test5 test6 test7
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
good job
3、I did my homework and watched TV。 On Sunday morning ,
good job
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。
[root@mvxl2685 test]# sed '/ing/i good job' test.txt #在匹配行前面插入
#!/bin/bash
#test test1 test2 test3
#test4 test5 test6 test7
1、Last weekend, I was busy。
good job
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
good job
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。
[root@mvxl2685 test]# sed '/ing/c good job' test.txt #修改匹配行
#!/bin/bash
#test test1 test2 test3
#test4 test5 test6 test7
1、Last weekend, I was busy。
good job
good job
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。

9、多行模式命令”N”、”D”、”P”

  • “N”命令:讀取下一行內容追加到模式空間的尾部。其和”n”命令不同之處在於:”n”命令會輸出模式空間的內容(除非使用了”-n”選項)並清空模式空間,然後才讀取下一行到模式空間,也就是說”n”命令雖然讀取了下一行到模式空間,但模式空間仍然是單行數據。而”N”命令在讀取下一行前,雖然也有自動輸出和清空模式空間的動作,但該命令會把當前模式空間的內容鎖住,使得自動輸出的內容為空,也無法清空模式空間,然後讀取下一行追加到當前模式空間中的尾部。追加時,原有內容和新讀取內容使用換行符”\n”分隔,這樣在模式空間中就實現了多行數據。即所謂的”多行模式”。 另外,當無法讀取到下一行時(到了文件尾部),將直接退出sed程序,使得”N”命令後的命令不會再執行,這和”n”命令是一樣的。
  • “D”命令:刪除模式空間中第一個換行符”\n”之前的內容,然後立即回到SCRIPT循環的頂端,即進入下一個SCRIPT循環。如果”D”刪除後,模式空間中已經沒有內容了,則SCRIPT循環自動退出進入下一個sed循環;如果模式空間還有剩餘內容,則繼續從頭執行SCRIPT循環。也就是說,”D”命令後的命令不會被執行。
  • “P”命令:輸出模式空間中第一個換行符”\n”之前的內容
[root@mvxl2685 test]# cat test.txt #查看文件內容
1、Last weekend, I was busy。
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
5、It was fun 。I had a very happy weekend。
[root@mvxl2685 test]# sed -n 'n;p' test.txt 
#首先把第一行加載到模式空間,然後執行n,把第二行加載到模式空間,覆蓋了第一條,然後執行p進行打印,輸出第2條數據,繼續自動加載第3條到模式空間,執行n,加載第4條覆蓋第3條,輸出第4條
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon, 4、I went to Hang zhou Meteorolgical Experience Hall with my family。 [root@mvxl2685 test]# sed -n 'N;p' test.txt
#加載第一條到模式空間,執行N,把第2條也加載進去,執行p,一起答應兩條,然後接着加載3,N命令加載4,p打印兩條,接着加載5,N命令執行為空,到了尾部,直接結束sed命令
1、Last weekend, I was busy。 2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon, 3、I did my homework and watched TV。 On Sunday morning , 4、I went to Hang zhou Meteorolgical Experience Hall with my family。 [root@mvxl2685 test]# sed -n '$!N;p' test.txt
#加載第一條到模式空間,執行N,把第2條也加載進去,執行p,一起答應兩條,然後接着加載3,N命令加載4,p打印兩條,接着加載5,到了尾部,跳過N命令,執行p,打印第5條
1、Last weekend, I was busy。 2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon, 3、I did my homework and watched TV。 On Sunday morning , 4、I went to Hang zhou Meteorolgical Experience Hall with my family。 5、It was fun 。I had a very happy weekend。 [root@mvxl2685 test]# sed -n '$!N;P' test.txt
#加載第一條到模式空間,執行N,把第2條也加載進去,執行P,這裡只打印\n前的數據,也就是第一條,然後接着加載3,覆蓋模式空間,N命令加載4,P打印第3條,接着加載5,到了尾部,跳過N命令,執行P,打印第5條
1、Last weekend, I was busy。 3、I did my homework and watched TV。 On Sunday morning , 5、It was fun 。I had a very happy weekend。 [root@mvxl2685 test]# sed 'N;D' test.txt
#加載第一條到模式空間,執行N,加載第二條到模式空間,D刪除\n前面的數據,保留第二條,然後加載第三條,刪除第二條,依次類推,
5、It was fun 。I had a very happy weekend。
[root@mvxl2685 test]# sed -n '/training/{N;p}' test.txt #打印匹配行以及下一行
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
3、I did my homework and watched TV。 On Sunday morning ,
[root@mvxl2685 test]# sed -n '/training/{N;s/\n//;p}' test.txt  #合併兩行
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,3、I did my homework and watched TV。 On Sunday morning ,
[root@mvxl2685 test]# sed -n '/training/{N;s/\n//p}' test.txt #合併兩行
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,3、I did my homework and watched TV。 On Sunday morning ,

10、buffer空間數據交換命令”h”、”H”、”g”、”G”、”x”

sed除了維護模式空間(pattern space),還維護另一個buffer空間:保持空間(hold space)。這兩個空間初始狀態都是空的。
絕大多數時候,sed僅依靠模式空間就能達到目的,但有些複雜的數據操作則只能藉助保持空間來實現。之所以稱之為保持空間,是因為它是暫存數據用的,除了僅有的這幾個命令外,沒有任何其他命令可以操作該空間,因此藉助它能實現數據的持久性。
保持空間的作用很大,它和模式空間之間的數據交換能實現很多看上去不能實現的功能,是實現sed高級功能所必須的,常用的幾個命令如下:

  • “h”命令:將當前模式空間中的內容覆蓋到保持空間。
  • “H”命令:在保持空間的尾部加上一個換行符”\n”,並將當前模式空間的內容追加到保持空間的尾部。
  • “g”命令:將保持空間的內容覆蓋到當前模式空間。
  • “G”命令:在模式空間的尾部加上一個換行符”\n”,並將當前保持空間的內容追加到模式空間的尾部。
  • “x”命令:交換模式空間和保持空間的內容。

注意,無論是交換、追加還是覆蓋,原空間的內容都不會被刪除。

 可能理解起來不是很好理解,畫個圖就輕鬆易懂了:

 

 在sed處理文件的時候,每一行都被保存在一個叫模式空間的臨時緩衝區中,除非行被刪除或者輸出被取消,否則所有被處理的行都將打印在屏幕上。接着模式空間被清空,並存入新的一行等待處理。

[root@mvxl2685 test]# sed -n '/training/p'  test.txt #打印匹配的行
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
[root@mvxl2685 test]# sed -n '/training/{h;n;G;p}'  test.txt #打印匹配的行和下一行,並交換位置
3、I did my homework and watched TV。 On Sunday morning ,
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
[root@mvxl2685 test]# sed -n '/training/{h;G;p}'  test.txt #兩次打印匹配的行
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
[root@mvxl2685 test]# sed  '1!G;h;$!d' test.txt  #逆序打印文件
5、It was fun 。I had a very happy weekend。
4、I went to Hang zhou Meteorolgical Experience Hall with my family。
3、I did my homework and watched TV。 On Sunday morning ,
2、On Saturday morning, my classmate and I had Math training class。 Saturday afternoon,
1、Last weekend, I was busy。

逆序打印思路如下:

 

 

參考地址

//www.cnblogs.com/f-ck-need-u/p/7478188.html

//www.cnblogs.com/f-ck-need-u/p/7488469.html

//www.linuxprobe.com/linux-sed-command.html

//blog.csdn.net/weixin_38149264/article/details/78074300

//blog.csdn.net/yangbin1265712/article/details/82994666

Tags: