1. 程式人生 > >“三劍客”之sed手中有劍

“三劍客”之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 morNING ,
4、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。

逆序列印思路如下:

 

 

參考地址:

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

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

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

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

https://blog.csdn.net/yangbin1265712/article/details/8299