Sed one line 筆記

這篇是當初看完Chinaunix論壇的帖子“拋磚引玉----翻譯加注sed1line”的筆記,最近無聊從Evernote翻出來。本文假設測試文件名為test.txt。

文件空行處理

1. 在文件中的每一行后面添加一個空行。

sed 'G' test.txt

解釋: Get命令是將保留空間的內容取出,并添加到當前模式空間的內容之后(添加一行)。當保留空間為空時,效果為往模式空間添加一行空行。

2. 保證文件中的每一行后面都有一行空行。和1不同的是,如果文件中本身包含空行,則合并成一行。

sed '/^$/d;G' test.txt

解釋:首先刪除空行,再添加一行空行。

3. 刪除偶數行

sed 'n;d' test.txt

解釋:n的意思讀入下一行,并且輸出當前行。當n讀入下一行之后,用d將其刪除。

4. 在匹配regex的行之前添加空行

sed '/regex/{x;p;x}' test.txt

解釋:x的意思是交換保留空間和模式空間的內容,首先保留空間為空,首次交換并用p打印空行;接著將原有內容交換回來,執行到命令末尾,自動輸出模式空間的內容。

5. 在匹配regex的行之后添加空行

sed '/regex/G' test.txt

解釋:參考1

6. 在匹配regex的行之前和之后都添加空行

sed '/regex/{x;p;x;G;}' test.txt

解釋:參考4、5

7. 每五行后添加一行空行

sed 'n;n;n;n;G'

或者

sed '0~5G' test.txt

解釋:很簡單,每次讀5行,再添加一個空行。第二種方法利用了GNU Sed的功能 addr~step,查看man sed。

文件行號處理

1. 給每一行添加行號,并且行號與行的非空白內容之間以制表符(t)分隔(保證左對齊)

類似:

1? aaa

20? aaa

相應的命令如下:

sed '=' test.txt | sed 'N;s/s*ns*/t/'

解釋:首先要取出并打印行號,可以用=命令打印行號,但是此時行號與行內容不在同一行輸出,因此需要將標準輸出重定向再次使用sed命令處理。使用Next命令讀入下一行,并將n(包括多余的空白)替換成一個制表符(t),再默認輸出打印。準確地說,這里使用了兩條sed命令。

2. 給每一行添加行號,并且行號與行的非空白內容之間以制表符(t)分隔(保證右對齊)

類似:(假設行號最多是3位數)

1? aaa

20? aaa

123? aaa

相應的命令如下:

sed '=' test.txt | sed 'N; s/^/? /;s/ *([ 0-9]{3})s*ns*/1t/'

解釋:前面同1,這里只介紹后面這部分:s/^/ /;s/ *([ 0-9]{3})s*ns*/1t/

這里首先在行首插入兩個空格,然后將空格與后面的行號(數字)部分,只保留三個字符。最后將回車與多余的空白替換成制表符。

3. 給文件每一行加上行號,但是僅當行非空時才打印行號。

sed '/./=' test.txt | sed '/./N; s/s*ns*/t/'

解釋:在sed中.不匹配n,因此用/./匹配非空行,其它同1。 但是如果要處理空行(包含空白符等的行),則需要:

sed '/[^[:blank:]]/=' test.txt | sed '/[^[:blank:]]/N; s/n/t/'

4. 統計行數

sed -n '$=' test.txt

解釋:使用-n阻止默認輸出,并只在最后一行的時候打印行號。

文本內容轉換和替換

1. 在Unix環境下,轉換DOS換行符為Unix格式

sed 's/^M//' test.txt

解釋:^M的鍵入方法,按住ctrl+v再敲回車。 這種處理和環境依賴性比較大,不是非常統一,這里只介紹一種。

2. 刪除行首和行尾空白

sed 's/^[[:blank:]]*|[[:blank:]]*$//' test.txt

解釋:這里再次用到了posix字符組,不多解釋。

3. 對每一行按照79列寬處理, 保持右對齊

類似

...................a

.................bba

................cccc

(超出的部分不處理)

sed -e ':a' -e 's/^.{1,78}$/ &/;ta' test.txt

解釋: 對單個命令本身不解釋了,這里用到了標簽、跳轉、替換等命令。 替換過程對不小于79列寬的行處理,在行首插入一個空格,直到等于79列寬為止,自動

輸出。

4. 對每一行按照79列寬處理,保持居中。

sed -e ':a' -e 's/^.{1,77}$/ & /; ta' test.txt

解釋:同3

5. 在每一行用bar替換foo

a. sed 's/foo/bar/' test.txt

b. sed 's/foo/bar/4' test.txt

c. sed 's/foo/bar/g' test.txt

d. sed 's/(.*)foo(.*foo)/1bar2/ test.txt

e. sed 's/(.*)foo/1bar/' test.txt

解釋:a在一行中只替換一次(首次出現);b替換第四次出現;c全局替換;d替換倒數第二個匹配;e替換最后一個匹配 。

6. 在包含或者不包含baz的行中替換foo為bar

sed '/baz/s/foo/bar/g' test.txt

sed '/baz/!s/foo/bar/g' test.txt

7. 反轉文件行的順序(類似tac命令,即從最后一行到第一行的順序打?。?/p>

sed '1!G;h;$!d' test.txt

解釋:首先1!G表示將除第一行之外,都先從保留空間取出內容并追加到模式空間的最后;h表示將模式空間的內容全部覆蓋到保留空間;然后 $!d表示將除最后一行之外的,都要將模式空間清除,并從頭開始(不打?。?。這些命令合起來就是,首先將一行的內容拷貝到臨時緩沖區(保留空間),然后清除當前行(不打?。僮x入下一行并從緩沖區取會保存的內容,因此行的順序就顛倒了。

8. 反轉文件中每一行的字符順序(類似rev命令)

sed '/n/!G;s/(.)(.*n)/&21/;//D;s/.//'

解釋:首先解釋一下這里使用到的一些特殊語法,//D,//為無內容,這是一種簡寫情況,默認使用上一次使用的正則表達式,這里就是(.)(.*n),因此等價于/(.)(.*n)/D。這條sed命令中過程是這樣的,首先該行如果不包含回車,則在末尾添加一個,對應命令中的/n/!G;然后開始替換,目的是把當前最前面的字母放到后面。

例如123n變成123n23n1;23n1變成23n3n21。然后使用D命令刪除第一行的內容。最后一個替換去掉首字符。該例子可以自己使用一個簡單的例子演練一遍就清楚了。

9. 將兩行合并成一行(類似paste命令)

sed '$!N;s/n/ /' test.txt

解釋:$!N表示除最后一行外,其它每行在讀入的時候,都將下一行讀進來添加到后面。接著用替換命令替換回車為空格。如果$!N改成N在這里不會出現問題,但是要記住的是,當到最后一行時,執行N命令將不會再讀入新行,結果是sed退出。不會執行接下來的命令。

10. 如果一行以“”結束,則合并下一行內容到當前行之后。

sed -e ':a' -e '/$/N; s/n/ /; ta' test.txt

解釋:同8類似,但是要考慮合并多行,因此需要做循環處理,這里使用標簽來達到這個目的。

11. 如果一行以等號開始,則合并這一行至上一行,并替換等號為空格

sed -e ':a' -e '$!N;s/n=/ /;ta;P;D' test.txt

解釋:同9類似,不過這里要讀入下一行之后,判斷'n='則替換成空格, 如果替換成功,則繼續讀入下一行(標簽跳轉);否則, 打印并刪除模式空間中的第一行。

D命令不會導入新的行讀入。

12. 給數字串加逗號,例如把“1234567”變成“1,234,567”

sed -e ':a' -e 's/([0-9])([0-9]{3})($|,)/1,2/;ta' test.txt

或者

sed -e ':a' -e 's/(.*[0-9])([0-9]{3})/1,2/;ta' test.txt

解釋:這里要使用標簽進行循環處理,關鍵點在正則表達式的書寫上。第二種寫法更加簡練。

13. 給帶有小數點和鉛的數字加上逗號

sed ':a;s/(^|[^0-9.])([0-9]+)([0-9]{3})/12,3/g;ta' test.txt

或者

sed ':a;s/^(-?[0-9]+)([0-9]{3})/1,2/g;ta' test.txt

解釋:同11,要注意負號和小數點,因此要加上開始標記^和-。

選擇性輸出行

1. 打印一個文件的前10行(類似head命令)

sed -n '1,10p' test.txt

或者

sed '10q' test.txt

解釋:顯然第二種方法比第一種方法效率高。q退出命令,表明在第10行的時候自動退出,不再讀入新的輸入行。

2. 打印一個文件的第一行。

sed 'q' test.txt

解釋:同上,在讀入第一行之后就退出,但是仍打印第一行的內容。

3. 打印一個文件的倒數10行(類似tail命令)

sed ':a;$q;N;11,$D;ba'

解釋:如果只看 ':a;$q;N;ba',效果就是一直將下一行追加到模式空間,最后達到最后一行的時候退出,并打印模式空間的內容。但是當變成':a;$q;N;11,$D;ba',11,$D表示如果行超過10行,則將模式空間的第一行刪除,同時ba跳轉到開頭,再次讀入下一行,保持模式空間的行數在10行。這樣看起來就是模式空間的最前面的一行被刪除,同時將新的一行追加到末尾處,當循環結束時,模式空間中保存的就是文件的最后10行。

4. 打印一個文件的倒數兩行(類似tail -2)

sed ':a;$q;N;3,$D;ba'

或者

sed '$!N;$!D' test.txt

解釋:第一種方法同3一樣。第二種方法,$!的意思是不在最后一行上執行命令。N命令不解釋,D命令是刪除模式空間的第一行,并且跳轉到命令開頭重新執行,并且當模式空間仍有內容時,不讀入新的輸入行。這一句的意思透露出兩點:

1) D命令之后的命令不會執行,而是跳轉到開頭,同時也不會自動輸出當前模式空間的內容。

2) 模式空間不為空,則不會自動讀入下一行的數據,除非使用N命令讀入下一行。

因此,$!N;$!D,將下一行讀入模式空間,并且將模式空間的第一行刪除,除非遇到最后一行,因此當循環結束時,模式空間中包含倒數兩行,完成要求,打印輸出。

5. 打印一個文件的最后一行(類似tail -1)

sed ':a;$q;N;2,$D;ba' test.txt

或者

sed -n '$p' test.txt

或者

sed '$!d' test.txt

6. 打印匹配“regex”行(類似grep)

sed -n '/regex/p' test.txt

或者

sed '/regex/!d' test.txt

解釋:同5類似

7. 打印不匹配“regex”行(類似grep -v)

sed -n '/regex/!p' test.txt

或者

sed '/regex/d' test.txt

解釋:同6。

8. 打印匹配“regex”之前的那一行。

sed -n '$!N;/regex/!D;/regex/P'

或者

sed -n '/regex/{g;1!p;};h'

解釋:第一方法理解起來比較簡單,讀入下一行到模式空間,并且判斷是否包含regex,如果匹配,則打印模式空間中的第一行,如果不匹配,則刪除模式空間的第一行,循環處理。(這種方法有問題嗎?)

第二種方法,如果沒遇到匹配行,則將當前行拷貝到保持空間,然后讀入下一行,如果匹配,則將保存的行從保持空間中提取到模式空間,并且打印(假如第一行就匹配則不打?。?。

9. 打印奇數行

sed -n 'N;P' test.txt

或者

sed -n '1~2p' test.xt

解釋:第一種方法,N讀入下一行到模式空間,P打印模式空間中的第一行,然后自動輸出被關閉,進入下一次循環,重新讀入新的一行到模式空間(自動讀入新行,非N,因此模式空間的內容被清除再讀入新行),再執行N;P,同樣打印模式空間的第一行。效果等同于打印奇數行。第二種方法,比較簡單,不過用到GNU Sed的特殊地址表示方法,addr~step,因此只在1,3,5,7等奇數行才打印行的內容。

10. 打印匹配“regex”那一行的后一行。

sed -n '/regex/{n;p}' test.txt

解釋:如果找到匹配的行,則讀取下一行,并且打印輸出。

11. 打印匹配“regex”那一行的前后一行,并且打印匹配行的行號(類似grep -A1 -B1)

sed -n '/regex/{=;x;1!p;g;$!N;p;D;}; h' test.txt

解釋: 如果不匹配,則先把該行保存到保持空間暫時記錄下來;如果找到匹配行,則打印該行的等號,并且將模式空間的內容和保持空間的內容交換,隨即打印模式空間的內容(第一行除外,同10);交換之后,再次將保持空間的內容恢復到模式空間(即當前匹配行),再讀入下一行(注意$!N),打印模式空間的所有內容(非P),打印完之后,清除模式空間的第一行的內容。進入下一個循環。注意此時,保持空間同樣保存著當前的輸入行。

12. 假設段落以空行分隔,打印包含“regex”的段落。

sed '/./{H;$!d};x;/regex/!d' test.txt

sed '/./{1h;1!H;$!d};x;/regex/!d' test.txt

解釋:思路很簡單,首先將讀入段落的內容,并依次將段落的第一行追加到保持空間備份,然后在保持空間中查找匹配單詞。但是第一種方法的輸出結果會在開始處多一個空行,第二種方法的目的是去掉多輸出的一個空行。

13. 打印長于65個字符的行

sed -n '/^.{65}/p' test.txt

解釋:正則表達式的應用。

14. 打印第52行

sed '52q;d' test.txt

解釋:效率比一般方法高

15. 從第三行開始,每隔7行打印機一行

sed -n '3~7p' test.txt

sed -n '3,${p;n;n;n;n;n;n;}' test.txt

解釋:比較簡單

選擇性刪除某些行

1. 刪除文件中連續并且重復的行,只保留第一行(類似uniq命令)

sed -n "$!N;/^(.*)n1$/!P;D' test.txt

解釋:讀入下一行,然后用正則判斷兩行是否一樣,如果一樣,則不打印,并且刪除同樣行中的第一行,再循環處理。

2. 刪除文件中重復的,但不連續的行,注意不要溢出保持空間的緩沖區大小。

不知道

3. 刪除一個文件中前10行

sed '1,10d' test.txt

解釋:比較簡單

4. 刪除一個文件中最后1行

sed '$d' test.txt

5. 刪除一個文件中最后2行

sed 'N;$!P;$!D;$d' test.txt

解釋:使用N讀入一行,并且如果新讀入的下一行不是最后一行,則打印模式空間中的第一行,并且刪除;如果新讀入的一行是文件的最后一行,則刪除模式空間中的所有內容(即倒數兩行)。

6. 刪除一個文件中最后10行;

sed ':a;$d;N;11,${P;D};ba' test.txt

sed ':a;$d;N;2,10ba;P;D' test.txt

sed -n ':a;1,10!{P;N;D};N;ba'

解釋:第一種方法參考前面的打印文件的最后10行內容。第二種方法,首先不停讀入下一行的內容,直到讀入第11行,此時模式空間中包含11行,打印第一行的內容并刪除,然后判斷最后讀入的那一行是不是最后一行,如果是,則刪除模式空間中的內容(一共10行,即倒數10行);如果不是,則繼續讀入下一行,打印模式空間中的第一行并刪除。循環直到最后一行為止。第一種方法,首先將讀入前10行的內容,如果讀到第10行之后(11行開始),首先打印模式空間的第一行,并讀入下一行,再刪除第一行,循環處理;始終保證模式空間中包含10行的內容,當在最后一行之后,再讀新行會導致sed退出,并打印模式空間的內容。

7. 每8行刪除1行

sed '0~8d' test.txt

解釋:比較簡單。

8. 刪除所有空行

sed '/^$/d' test.txt

或者

sed '/./!d' test.txt

解釋:都比較簡單,第一個匹配空行,第二個匹配非空行。

9. 壓縮文件中的連續空行為一行,包括文件開頭和結尾(類似cat -s)

sed '/^$/N;/n$/D' test.txt

解釋:遇到空行,則繼續讀入下一行,如果讀入的一行依然是空行,則刪除第一行(空行),循環處理。

10. 刪除文件中的連續空行,但保留前兩個空行

sed '/^$/N;/n$/N;//D' test.txt

解釋:同9,不過不是壓縮空行為一行,而是兩行,因此在9的基礎上再加一步,//D中正則為空,默認使用上次的正則表達式。

11. 刪除文件開頭的空行

sed '/./, $!d' test.txt

解釋:刪除第一行非空行之前的所有空行。

12. 刪除文件結尾的所有空行

sed ':a;/^n*$/{$d;N;ba}' test.txt

解釋:如果碰到一個空行,如果不是最后一行,則繼續讀入下一行,跳到開頭,判斷模式空間內是否全是空行。如果讀到最后一行,而且,模式空間內的內容都是空行,則刪除,這意味著刪除了所有結尾處的空行。

13. 刪除每個段落的最后一行

sed -n '/^$/{p;h;};/./{x;/./p}' test.txt

解釋:如果遇到空行,則直接打印,并且將空行保存到保持空間,這樣會覆蓋空行的上一行內容,如果上一行不為空行,內容就不打印了,而如果上一行是空行,因為之前已經打印了,所以這里不會有影響;如果不是空行,則交換保持空間和模式空間的內容,保持空間保存的是上一行的內容,如果上一行不是空行,則打印。

轉自:團子的小窩, 本文固定鏈接:sed1line 筆記

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Sed工具工作原理及特性 1. sed是流編輯器,每一次讀取一行到內存中,即稱之為模式空間(pattern spa...
    魏鎮坪閱讀 11,037評論 0 12
  • sed與awk實例 文本間隔 在每一行后面增加一空行 將原來的所有空行刪除并在每一行后面增加一空行。這樣在輸出的文...
    stuha閱讀 1,921評論 0 21
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數據革命閱讀 12,239評論 2 33
  • 本文承接之前寫的三十分鐘學會AWK一文,在學習完AWK之后,趁熱打鐵又學習了一下SED,不得不說這兩個工具真的堪稱...
    mylxsw閱讀 4,417評論 3 74
  • sed篇總共分成6章:(簡書版) Sed&awk筆記之sed篇:簡單介紹 Sed&awk筆記之sed篇:模式空間與...
    magic5650閱讀 842評論 0 3