sed詳解

sed詳解

之前,寫過一篇grep正則表達式的文章。這篇記錄下與grep命令具有類似相同功能的兩個命令,sedawkgrep是文本搜索工具,sed是非交互式流編輯器,awk是一種文本格式化工具。

sed是一個非交互式的流編輯器。所謂非交互式,是指使用sed只能在命令行下輸入編輯命令來編輯文本,然後在屏幕上查看輸出;而所謂流編輯器,是指sed每次只從文件(或輸入)讀入一行,然後對該行進行指定的處理,並將結果輸出到屏幕(除非取消了屏幕輸出又沒有顯式地使用打印命令),接着讀入下一行。整個文件像流水一樣被逐行處理然後逐行輸出。

下面我們看一下sed的工作過程。

sed不是在原輸入上直接進行處理的,而是先將讀入的行放到緩衝區中,對緩衝區裏的內容進行處理,處理完畢後也不會寫回原文件(除非用shell的輸出重定向來保存結果),而是直接輸出到屏幕上。sed運行過程中維護着兩個緩衝區,一個是活動的“模式空間(pattern space)”,另一個是起輔助作用的“暫存緩衝區(holding space)”。一般情況下,每當運行sedsed首先把第一行裝入模式空間,進行處理後輸出到屏幕,然後將第二行裝入模式空間替換掉模式空間裏原來的內容,然後進行處理,以此類推。

如圖:

wKioL1YHrEWBadPAAACfu8WWyh4924.jpg 

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]#

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章