sed詳解
之前,寫過一篇grep正則表達式的文章。這篇記錄下與grep命令具有類似相同功能的兩個命令,sed和awk。grep是文本搜索工具,sed是非交互式流編輯器,awk是一種文本格式化工具。
sed是一個非交互式的流編輯器。所謂非交互式,是指使用sed只能在命令行下輸入編輯命令來編輯文本,然後在屏幕上查看輸出;而所謂流編輯器,是指sed每次只從文件(或輸入)讀入一行,然後對該行進行指定的處理,並將結果輸出到屏幕(除非取消了屏幕輸出又沒有顯式地使用打印命令),接着讀入下一行。整個文件像流水一樣被逐行處理然後逐行輸出。
下面我們看一下sed的工作過程。
sed不是在原輸入上直接進行處理的,而是先將讀入的行放到緩衝區中,對緩衝區裏的內容進行處理,處理完畢後也不會寫回原文件(除非用shell的輸出重定向來保存結果),而是直接輸出到屏幕上。sed運行過程中維護着兩個緩衝區,一個是活動的“模式空間(pattern space)”,另一個是起輔助作用的“暫存緩衝區(holding space)”。一般情況下,每當運行sed,sed首先把第一行裝入模式空間,進行處理後輸出到屏幕,然後將第二行裝入模式空間替換掉模式空間裏原來的內容,然後進行處理,以此類推。
如圖:
sed命令格式
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
OPTION:
-r: 支持擴展正則表達式; -n: 靜默模式; -e script1 -e script2 -e script3:指定多腳本運行; -f /path/to/script_file:從指定的文件中讀取腳本並運行; -i: 直接修改源文件;
地址定界:
#: 指定行; $: 最後一行; /regexp/:任何能夠被regexp所匹配到的行; \%regexp%:同上,只不過換作%爲regexp邊界符; startline,endline==#,#:從startline到endline #,/regexp/:從#行開始,到第一次被/regexp/所匹配到的行結束,中間的所有行; /regexp1/,/regexp2/:從第一次被/regexp1/匹配到的行開始,到第一次被/regexp2/匹配到的行結束,中間的所有行; #,+n:從#行開始,一直到向下的n行; first~step:指定起始行,以及步長;
sed的編輯命令
d: 刪除模式空間中的行; =:顯示行號; a\text:附加text i\text:插入text,支持\n實現多行插入; c\text:用text替換匹配到的行; p: 打印模式空間中的行; s/regexp/replacement/:替換由regexp所匹配到的內容爲replacement;g: 全局替換; w /path/to/somefile:把指定的內容另存至/path/to/somefile路徑所指定的文件中; r /path/from/somefile:在文件的指定位置插入另一個文件的所有內容,完成文件合併;
例子:
一、OPTIONS
1、sed默認使用參數-e,如果不指定“定界位置符”默認讀取文件所有行,不指定對文件的操作命令,默認爲打印p。
[root@centos bash]# [root@centos bash]# sed '' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then poor=$[$num1-$num2] num1=$poor elif [ $num2 -gt $num1 ];then poor=$[$num2-$num1] num2=$poor fi done echo $poor [root@centos bash]# sed -e '' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then poor=$[$num1-$num2] num1=$poor elif [ $num2 -gt $num1 ];then poor=$[$num2-$num1] num2=$poor fi done echo $poor [root@centos bash]#
2、-n選項,必須與地址定界一起使用,否則不打印任何信息,作用是取消默認對文件所有行的操作。
[root@centos bash]# sed -n '' a.sh [root@centos bash]# sed -n '1p' a.sh #!/bin/bash [root@centos bash]# sed '1p' a.sh #!/bin/bash #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then poor=$[$num1-$num2] num1=$poor elif [ $num2 -gt $num1 ];then poor=$[$num2-$num1] num2=$poor fi done echo $poor [root@centos bash]#
3、-r選項,使用擴展的正則表達式
[root@centos bash]# sed -n '/1|2/p' a.sh [root@centos bash]# [root@centos bash]# [root@centos bash]# sed -rn '/1|2/p' a.sh read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then poor=$[$num1-$num2] num1=$poor elif [ $num2 -gt $num1 ];then poor=$[$num2-$num1] num2=$poor [root@centos bash]#
4、-e選項,可以對一個文件執行多次sed命令,-e可以使用;代替
[root@centos bash]# sed -ne '1p;2p;4p' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do [root@centos bash]# [root@centos bash]# [root@centos bash]# sed -ne '1p' -e '2p' -e '4p' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do [root@centos bash]#
5、-f選項,指定文件,使sed按照文件的定義執行
[root@centos bash]# cat sed 1p 2p 4p [root@centos bash]# sed -n -f sed a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do [root@centos bash]#
6、-i選項,直接修改源文件
[root@centos bash]# sed -i '1p' a.sh [root@centos bash]# cat a.sh #!/bin/bash #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] let num1=$poor elif [ $num2 -gt $num1 ];then let poor=$[$num2-$num1] let num2=$poor fi done echo $poor [root@centos bash]#
二、地址定界
1、# 數字,用來指定文件第#行,上面的例子都是此種模式。不再舉例
2、$ 匹配最後一行
[root@centos bash]# sed -n '$p' a.sh echo $poor [root@centos bash]#
3、/regexp/:任何能夠被regexp所匹配到的行,可以使用正則表達式
例如上面-r所舉的例子,匹配1或2的行
4、\%regexp%:同上,只不過換作%爲regexp邊界符;
[root@centos bash]# sed -nr '\%1|2%p' a.sh read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] let num1=$poor elif [ $num2 -gt $num1 ];then let poor=$[$num2-$num1] let num2=$poor [root@centos bash]#
5、startline,endline==#,#:從startline到endline
[root@centos bash]# sed -n '1,4p' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do [root@centos bash]#
6、#,/regexp/:從#行開始,到第一次被/regexp/所匹配到的行結束,中間的所有行;
[root@centos bash]# sed -n '1,/let/p' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] [root@centos bash]#
7、/regexp1/,/regexp2/:從第一次被/regexp1/匹配到的行開始,到第一次被/regexp2/匹配到的行結束,中間的所有行;
[root@centos bash]# sed -n '/#/,/let/p' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] [root@centos bash]#
8、#,+n:從#行開始,一直到向下的n行
[root@centos bash]# sed -n '1,+2p' a.sh #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 [root@centos bash]#
9、first~step:指定起始行,以及步長
[root@centos bash]# sed -n '1~2p' a.sh #!/bin/bash if [ $num1 -gt $num2 ];then let num1=$poor let poor=$[$num2-$num1] fi echo $poor [root@centos bash]#
三、編輯命令
1、d 刪除模式空間中的行;
[root@centos bash]# sed -r '/1|2/d' a.sh #!/bin/bash fi done echo $poor [root@centos bash]#
2、= 顯示行號;
[root@centos bash]# sed '/1/=' a.sh #!/bin/bash 2 read -p "plz enter two integer:" -t 20 num1 num2 4 while [ $num1 != $num2 ];do 5 if [ $num1 -gt $num2 ];then 6 let poor=$[$num1-$num2] 7 let num1=$poor 8 elif [ $num2 -gt $num1 ];then 9 let poor=$[$num2-$num1] let num2=$poor fi done echo $poor [root@centos bash]#
3、a \text:附加text,在匹配行後添加text
[root@centos bash]# sed '/#/a\hello world!' a.sh #!/bin/bash hello world! read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] let num1=$poor elif [ $num2 -gt $num1 ];then let poor=$[$num2-$num1] let num2=$poor fi done echo $poor [root@centos bash]#
4、i \text:插入text,支持\n實現多行插入,在匹配的行前插入text
[root@centos bash]# sed '/#/i\hello\nworld!' a.sh hello world! #!/bin/bash read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] let num1=$poor elif [ $num2 -gt $num1 ];then let poor=$[$num2-$num1] let num2=$poor fi done echo $poor [root@centos bash]# [root@centos bash]# [root@centos bash]# sed -n '/#/i\hello\nworld!' a.sh hello world! [root@centos bash]#
5、c \text:用text替換匹配到的行;
[root@centos bash]# sed '/#/c\hello world!' a.sh hello world! read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] let num1=$poor elif [ $num2 -gt $num1 ];then let poor=$[$num2-$num1] let num2=$poor fi done echo $poor [root@centos bash]#
6、p: 打印模式空間中的行;
前面的例子很多,不再列舉。
7、s/regexp/replacement/:替換由regexp所匹配到的內容爲replacement。g: 全局替換;
[root@centos bash]# sed -n '2p' a.sh 123454321 [root@centos bash]# sed -n '2 s/1/A/p' a.sh A23454321 [root@centos bash]# sed -n '2 s/1/A/gp' a.sh A2345432A
如果沒有地址定界,則每行匹配要替換的字符,且只替換每行匹配到的第一個。
[root@centos bash]#sed -n 's/1/A/p' a.sh A23454321 read -p "plz enter two integer:" -t 20 numA num2 while [ $numA != $num2 ];do if [ $numA -gt $num2 ];then let poor=$[$numA-$num2] let numA=$poor elif [ $num2 -gt $numA ];then let poor=$[$num2-$numA] [root@centos bash]#
8、w /path/to/somefile:把指定的內容另存至/path/to/somefile路徑所指定的文件中;
[root@centos bash]# cat sed [root@centos bash]# sed -n '/#/w/root/Desktop/bash/sed' a.sh [root@centos bash]# cat sed #!/bin/bash [root@centos bash]#
9、r /path/from/somefile:在文件的指定位置插入另一個文件的所有內容,完成文件合併;
[root@centos bash]# sed '$ r/root/Desktop/bash/sed' a.sh #!/bin/bash 123454321 read -p "plz enter two integer:" -t 20 num1 num2 while [ $num1 != $num2 ];do if [ $num1 -gt $num2 ];then let poor=$[$num1-$num2] let num1=$poor elif [ $num2 -gt $num1 ];then let poor=$[$num2-$num1] let num2=$poor fi done echo $poor #!/bin/bash hello world #welcome here
sed的高級用法
sed的高級用法需要用到sed的另外一個“保持空間”。前面基本用法中也有提到模式空間,即爲處理文件中一行內容的一個臨時緩衝區。處理完一行之後就會把模式空間中的內容打印到標準輸出,然後自動清空緩存。
而這裏說的保持空間是sed中的另外一個緩衝區,此緩衝區正如其名,不會自動清空,但也不會主動把此緩衝區中的內容打印到標準輸出中。而是需要以下sed命令進行處理:
h:用模式空間中的內容覆蓋保持空間的內容;
H:把模式空間中的內容追加至保持空間中內容的後面;
g:從保持空間中取到其內容,並將其覆蓋模式空間中的內容;
G:從保持空間中取到其內容,並將其追加在模式空間中的內容的後面;
x:把保持空間和模式空間中的進行交換;
n:讀取匹配到的行的下一行至模式空間;(會覆蓋模式空間中的原有內容);
N:讀取匹配到的行的下一行至模式空間,追加在模式空間中原有內容的後面;
d:刪除模式空間中的內容;
D:刪除多行模式空間中的首行;
注意:命令功能可使用!取反;分號可用於分隔腳本;
舉例:
1、倒序顯示文件內容
[root@centos bash]# sed '1!G;h;$!d' sed f e d c b a #!/bin/bash [root@centos bash]# cat sed #!/bin/bash a b c d e f [root@centos bash]#
執行過程解析:
命令 sed ‘1!G;h;$!d’ sed 1、讀入第一行#!/bin/bash,匹配1!G,不執行G;h命令沒有定界,執行h,從模式空間覆蓋到保持空間;不匹配$!d,刪除模式空間的內容 2、讀入第二行a,不匹配1!G,執行G,從保持空間追加到模式空間,變成:a\n#!/bin/bash;執行h,從模式空間覆蓋到保持空間,保持空間由#!/bin/bash變成:a\n#!/bin/bash;不匹配$!d,刪除模式空間的內容; 3、讀入第三行b,匹配模式與第二行相同,保持空間內容變爲:b\na\n#!/bin/bash 4、讀入第四行c,匹配模式與第二行相同,保持空間內容變爲:c\nb\na\n#!/bin/bash 5、讀入第五行d,匹配模式與第二行相同,保持空間內容變爲:d\nc\nb\na\n#!/bin/bash 6、讀入第六行e,匹配模式與第二行相同,保持空間內容變爲:e\nd\nc\nb\na\n#!/bin/bash 7、讀入第七行f,匹配模式與第二行相同,保持空間內容變爲:f\ne\nd\nc\nb\na\n#!/bin/bash;但最後一行匹配$!d,所以不刪除模式空間內容,模式空間內容與保持空間相同,並默認打印模式空間內容。
2、在文件中每行後加入空行
[root@centos bash]# sed 'G' sed #!/bin/bash a b c d e f [root@centos bash]#
3、d 刪除行
[root@centos bash]# sed '1d' sed a b c d e f [root@centos bash]#
4、保留奇數行
[root@centos bash]# sed 'n;d' sed 1 3 5 [root@centos bash]#
5、只打印偶數行
[root@centos bash]# sed -n 'n;p' sed 2 4 6 [root@centos bash]#