這篇是當初看完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 筆記