sed詳解css
以前,寫過一篇grep正則表達式的文章。這篇記錄下與grep命令具備相似相同功能的兩個命令,sed和awk。grep是文本搜索工具,sed是非交互式流編輯器,awk是一種文本格式化工具。正則表達式
sed是一個非交互式的流編輯器。所謂非交互式,是指使用sed只能在命令行下輸入編輯命令來編輯文本,而後在屏幕上查看輸出;而所謂流編輯器,是指sed每次只從文件(或輸入)讀入一行,而後對該行進行指定的處理,並將結果輸出到屏幕(除非取消了屏幕輸出又沒有顯式地使用打印命令),接着讀入下一行。整個文件像流水同樣被逐行處理而後逐行輸出。shell
下面咱們看一下sed的工做過程。centos
sed不是在原輸入上直接進行處理的,而是先將讀入的行放到緩衝區中,對緩衝區裏的內容進行處理,處理完畢後也不會寫回原文件(除非用shell的輸出重定向來保存結果),而是直接輸出到屏幕上。sed運行過程當中維護着兩個緩衝區,一個是活動的「模式空間(pattern space)」,另外一個是起輔助做用的「暫存緩衝區(holding space)」。通常狀況下,每當運行sed,sed首先把第一行裝入模式空間,進行處理後輸出到屏幕,而後將第二行裝入模式空間替換掉模式空間裏原來的內容,而後進行處理,以此類推。緩存
如圖:bash
sed命令格式編輯器
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
OPTION:ide
-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的編輯命令spa
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:在文件的指定位置插入另外一個文件的全部內容,完成文件合併;
例子:
1、OPTIONS
一、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]#
二、-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]#
三、-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]#
四、-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]#
五、-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]#
六、-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]#
2、地址定界
一、# 數字,用來指定文件第#行,上面的例子都是此種模式。再也不舉例
二、$ 匹配最後一行
[root@centos bash]# sed -n '$p' a.sh echo $poor [root@centos bash]#
三、/regexp/:任何可以被regexp所匹配到的行,可使用正則表達式
例如上面-r所舉的例子,匹配1或2的行
四、\%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]#
五、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]#
六、#,/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]#
七、/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]#
八、#,+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]#
九、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]#
3、編輯命令
一、d 刪除模式空間中的行;
[root@centos bash]# sed -r '/1|2/d' a.sh #!/bin/bash fi done echo $poor [root@centos bash]#
二、= 顯示行號;
[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]#
三、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]#
四、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]#
五、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]#
六、p: 打印模式空間中的行;
前面的例子不少,再也不列舉。
七、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]#
八、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]#
九、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:刪除多行模式空間中的首行;
注意:命令功能可以使用!取反;分號可用於分隔腳本;
舉例:
一、倒序顯示文件內容
[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 一、讀入第一行#!/bin/bash,匹配1!G,不執行G;h命令沒有定界,執行h,從模式空間覆蓋到保持空間;不匹配$!d,刪除模式空間的內容 二、讀入第二行a,不匹配1!G,執行G,從保持空間追加到模式空間,變成:a\n#!/bin/bash;執行h,從模式空間覆蓋到保持空間,保持空間由#!/bin/bash變成:a\n#!/bin/bash;不匹配$!d,刪除模式空間的內容; 三、讀入第三行b,匹配模式與第二行相同,保持空間內容變爲:b\na\n#!/bin/bash 四、讀入第四行c,匹配模式與第二行相同,保持空間內容變爲:c\nb\na\n#!/bin/bash 五、讀入第五行d,匹配模式與第二行相同,保持空間內容變爲:d\nc\nb\na\n#!/bin/bash 六、讀入第六行e,匹配模式與第二行相同,保持空間內容變爲:e\nd\nc\nb\na\n#!/bin/bash 七、讀入第七行f,匹配模式與第二行相同,保持空間內容變爲:f\ne\nd\nc\nb\na\n#!/bin/bash;但最後一行匹配$!d,因此不刪除模式空間內容,模式空間內容與保持空間相同,並默認打印模式空間內容。
二、在文件中每行後加入空行
[root@centos bash]# sed 'G' sed #!/bin/bash a b c d e f [root@centos bash]#
三、d 刪除行
[root@centos bash]# sed '1d' sed a b c d e f [root@centos bash]#
四、保留奇數行
[root@centos bash]# sed 'n;d' sed 1 3 5 [root@centos bash]#
五、只打印偶數行
[root@centos bash]# sed -n 'n;p' sed 2 4 6 [root@centos bash]#