首頁 > 軟體

Linux基礎知識之sed流編輯器詳解

2020-06-16 17:34:43

之前介紹了三大文字編輯器的grep,這裡介紹比grep功能更強的sed流編輯器

Linux文字處理工具grep和正規表示式及egrep與grep區別  http://www.linuxidc.com/Linux/2016-08/134046.htm

sed是什麼?

sed是Stream EDitor的縮寫,man中對sed的簡介為

sed - stream editor for filtering and transforming text

它的主要功能是對文字的過濾與替換。


sed的工作原理

sed的工作過程:sed是一個流編輯器,所謂流編輯器是指sed每次只從檔案或stdin中讀入一行,將讀入的行儲存至模式空間然後根據指定的要求對其進行處理,並將處理後的結果輸出至螢幕,接著讀入下一行,整個文字的過程如流水線般被逐行處理後輸出。

sed對內容的處理方式:sed不是在原檔案中或原輸入上直接進行處理的,它將讀入的行放入快取區,對快取區裡的內容進行處理,處理完畢後預設不會寫入或覆蓋原始檔,而是直接輸出到螢幕上。

它有兩個記憶體緩衝區分別叫做:模式空間(pattern space)、保持空間也有稱作暫存快取區(holding space)。

一般情況下sed首先把第一行裝入模式空間,進行處理後輸出螢幕,然後第二行裝入模式空間替換掉模式空間裡原來的內容,再進行處理,依次迴圈,直至結束。

下面是我對sed工作流程的理解圖。

1、sed每次將stdin中的內容中的一行讀入模式空間

2、之後根據模式空間中的匹配條件進行匹配,符合條件進入下一階段即普通編輯,不滿足則預設至標準輸出,結束

3、普通編輯之後分三個階段,1)普通編輯之後選擇性顯示至STDOUT,結束;2)進入holding space進行高階編輯,編輯結束後選擇性顯示至模式空間,之後再次根據編輯命令重複2-3過程;3)若是出現多編輯命令則需要再返回模式空間根據編輯條件再次進行2-3步驟。

限於個人理解程度上述的理解免不了跟真實的工作流程有些出入,大家要抱著質疑的態度去看,我寫的不一定都是對的,不過錯的應該不至於很多。


sed語法

sed OPTIONS... <SCRIPT> [INPUTFILE...]

[SCRIPT]:可以理解為地址定界加編輯命令。

常用選項

         -n:不輸出模式空間中的內容至螢幕;通俗點可以理解為它可以自動過濾掉模式空間中未匹配到的行,-n 要與命令編輯中的p合用(命令編輯見下文),用於顯示模式空間中被匹配到的內容。

            suppress automatic printing of pattern space

         -n的具體應用見後面的sed編輯高階命令演示

         -e:多點編輯

            add the script to the commands to be executed

         -f:每行一個編輯命令

            add the contents of script-file to the commands to be executed

         -r:使用擴充套件表示式

            use extended regular expressions in the script.

         -i:直接編輯原檔案

         edit files in place (makes backup if SUFFIX supplied)

SCRIPT

之前對這塊很迷糊,因為info中sed顯示語法有[]表示可加可不加,於是就在sed後直接加想要編輯的文字

於是就出現如下情況

1
2
[root@localhost test]# sed sed1
sed:-e 表示式 #1,字元 4:未終止的“s”命令

報錯資訊沒找到終止的限制條件,所以上面的sed語法格式並不準確。

通過實驗,sed可以不加[OPTION]但是[SCRIPT]則必須新增

SCRIPT分兩部分地址定界(用於限定編輯文字的範圍)、編輯命令(用於對匹配到的內容進行什麼樣的操作或編輯),前者可少後者必不可少,如果沒有編輯的命令會發生如下錯誤

1
2
3
4
5
6
7
8
9
10
[root@localhost test]# sed '1' cat1
sed:-e 表示式 #1,字元 1:遺漏命令
[root@localhost test]# cat cat1
hi,everyone
now I will show how to use cat
[root@localhost test]# sed 'p' cat1
hi,everyone
hi,everyone
now I will show how to use cat
now I will show how to use cat

地址定界: 

        1、空地址:對全文處理

        2、單地址:

          #:指定行;

          /pattern/:被此模式所匹配到的每一行;

        3、地址範圍:

         #,#:從#開始到#結束的所有行

         #,+#:從#開始向下至+#的行之間的所有行

         #,/pat1/ 從#開始至匹配到第一次出現/pat1/模式的行之間的所有行

         /pat1/,/pat2/:第一次匹配到/pat1/的行到第一次匹配到/pat2/的行之間的所有行

        4、步進:~

        1~2:所有奇數行          2~2:所有偶數行

編輯命令:若少了編輯命令會報錯,編輯命令在SCRIPT中至少出現一次。

        d:刪除模式空間中匹配到的內容       Delete pattern space

        a text 在行後面插入文字“text”,支援使用n實現多行插入

        Append text, which has each embedded newline  preceded  by  a  back slash.

        i text 在行前面插入文字“text”,支援使用n實現多行插入

        Insert  text,  which  has  each embedded newline preceded by a back slash.

        c text 把匹配到的行替換為此處指定的文字“text”

       Replace the selected lines with text, which has each  embedded  new line preceded by a backslash.

        w filename 儲存模式空間匹配的行至指定的檔案中

              Write the current pattern space to filename.

        r filename 讀取指定檔案內容至當前檔案被模式匹配到的行檔案後合併

              Append text read from filename.

        =  : 為模式匹配到的行列印行號    Print the current line number.

       : 條件取反(它比較特殊,它必須跟其他編輯命令一起使用

      s/regexp/replacement/ : 查詢替換,其分隔符可自行指定,常用有s@@@,s###

      它有一個特殊的用法s//x&/:表示將被查詢的內容在其前面新增x內容

                        s//&x/:表示將被查詢的內容在其後面新增x內容

                        &代表被查詢的內容

1
2
3
4
5
6
7
8
9
[root@localhost test]# cat cat1
hi,everyone
now I will show how to use cat
[root@localhost test]# sed 's/e/&#/' cat1 
hi,e#veryone
now I will show how to use# cat
[root@localhost test]# sed 's/e/#&/' cat1 
hi,#everyone
now I will show how to us#e cat

                    p  :顯示替換成功的行    

                    g  :全域性替換

                    w  filename : 將替換成功的結果儲存至指定檔案中

      查詢替換在sed中應用很廣,下面很多例子都是以sed的替換功能實現的

        p  :顯示當前模式空間中的內容    Print the current pattern space.

 

註:同時使用多個編輯命令,命令之間要用;隔開(!除外)

例子如下:

1
2
3
4
5
6
7
[root@localhost test]# sed 'p;=' cat1
hi,everyone
1
hi,everyone
now I will show how to use cat
2
now I will show how to use cat

 

範例演示

1、刪除/etc/grub2.conf檔案中所有以空白開頭的行行首的空白字元

1
sed 's#^[[:space:]]+##' /etc/grub2.cfg

這裡##是將前面匹配到的內容刪除的意思,上面文字內容太多,就不擷取了。

2、刪除/etc/fstab檔案中所有以#開頭,後面至少跟一個空白字元的行的行首的#號及#後面的所有空白字元

1
sed 's@^#[[:space:]]+@@' /etc/fstab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost test]# cat /etc/fstab 
#
# /etc/fstab
# Created by anaconda on Tue Jul 19 23:52:41 2016
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/CentOS-root /                       xfs     defaults        0 0
UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
[root@localhost test]# sed 's@^#[[:space:]]+@@' /etc/fstab
#
/etc/fstab
Created by anaconda on Tue Jul 19 23:52:41 2016
#
Accessible filesystems, by reference, are maintained under '/dev/disk'
See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

3、在/etc/fstab每一行行首增加#號

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cat /etc/fstab                           
#
# /etc/fstab
# Created by anaconda on Tue Jul 19 23:52:41 2016
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
 sed 's@^@#&@' /etc/fstab
#
##
## /etc/fstab
## Created by anaconda on Tue Jul 19 23:52:41 2016
##
## Accessible filesystems, by reference, are maintained under '/dev/disk'
## See man pages fstab(5), findfs(8), mount(8) and/or blkid(8for more info
##
#/dev/mapper/centos-root /                       xfs     defaults        0 0
#UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot                   xfs     defaults        0 0
#/dev/mapper/centos-swap swap                    swap    defaults        0 0

4、處理/etc/fstab路徑,使用sed命令取出其目錄名和基名

目錄名

1
2
[root@localhost test]# echo '/etc/fstab' | sed -r 's#(.*/)([^/]+/?)#1#' 
/etc/

基名

1
2
[root@localhost test]# echo '/etc/fstab' | sed -r 's#(.*/)([^/]+/?)#2#'
fstab

 

sed高階編輯命令:

    h:把模式空間中的內容覆蓋至保持空間中;

    H:把模式空間中的內容追加至保持空間中;

    g:把保持空間中的內容覆蓋至模式空間中;

    G:把保持空間中的內容追加至模式空間中;

    x:把模式空間中的內容與保持空間中的內容互換;

    n:覆蓋讀取匹配到的行的下一行至模式空間中;

    N:追加讀取匹配到的行的下一行至模式空間中;

    d:刪除模式空間中的行;

    D:刪除多行模式空間中的所有行;

我知道看了上面這些高階命令一定很暈,下面通過5個例子來理一下使用sed高階編輯命令的思路

高階編輯命令範例演示:

1、    sed  -n  'n;p'  FILE:

''內意思:將讀取到的行的下一行內容顯示至模式空間

-n 'p':將模式空間中被匹配到的內容顯示至螢幕

二者結合起來就是只顯示偶數行。

1
2
3
4
5
[root@localhost test]# cat -n cat1
     1  hi,everyone
     2  now I will show how to use cat
[root@localhost test]# sed -n 'n;p' cat1
now I will show how to use cat


2    sed  '1!G;h;$!d'  FILE:

這個命令按'x;x;x'中的;號分割分為三部分:

1、1!G:除讀取的第一行都進行G編輯

2、h:將模式空間中的內容覆蓋至保持空間中

3、$!d:刪除非最後一行的內容

命令解釋完了,我想大家對此應該還是一頭霧水,那麼就具體說明這個命令的意思:

1)讀取文字資訊的1行內容至模式空間,由於是第一行所以模式空間中的1行不進行G操作,之後觸發h,將模式空間中的1行放入保持空間中,再之後觸發$!d,由於1行不是最後一行,所以將模式空間中的1行刪除;

2)讀取2行內容至模式空間,由於不是1行所以觸發G操作,將保持空間中1行追加到2行後面,此時模式空間中的順序內容為2行,1行,之後h命令將模式空間中內容覆蓋至保持空間中,此時保持空間內容為2行,1行,因為2行不是最後一行,所以$!d刪除模式空間中內容;

3)上述過程不斷重複,直到最後一行時不進行d操作,此時模式空間中的第一行就是原檔案的最後一行。

因此這個命令就是原檔案內容反過來的排列。

1
2
3
4
5
6
[root@localhost test]# cat cat1
hi,everyone
now I will show how to use cat
[root@localhost test]# sed '1!G;h;$!d' cat1   
now I will show how to use cat
hi,everyone

3、    sed  '$!d'  FILE:

經過了上面兩個命令的磨練,這個就顯得簡單了。

'$!d':不是最後一行則刪除

意思是說模式空間中只保留文字的最後一行

1
2
[root@localhost test]# sed '$!d' cat1
now I will show how to use cat

 

4、    sed '/^$/d;G' FILE

'/^$/d':查詢模式空間中的每行是否包含空白行,若包含則將其刪除

G:將保持空間中的內容追加至模式空間中的每行後面

刪除原有的所有空白行,而後為所有的非空白行後新增一個空白行;

二者結合在一起即:保證指定檔案每一行後方有且只有一個空白行

1
2
3
4
[root@localhost test]# sed '/^$/d;G' cat1
hi,everyone
  
now I will show how to use cat

5、    sed  'n;d'  FILE:顯示奇數行;

這個就很簡單了,大家按照sed的工作原理及編輯命令n與d很容易就能明白其所表達的意思

1
2
3
4
5
[root@localhost test]# cat cat1
hi,everyone
now I will show how to use cat
[root@localhost test]# sed 'n;d' cat1
hi,everyone

 


學習sed的一些感受

    學習sed如果對於sed的編輯命令或高階命令很困惑,那麼不妨試試照著我上面的sed工作流程圖,一步一步的自己畫圖分析每一步所代表的意思。這既能加強自己對sed這個工具的了解也可有助於理清我們的使用思路。這是我在學習過程中覺得很有用的一種方法。

    sed這個工具它的精髓在於它的替換,替換的精髓在於精確匹配,而精確匹配又離不開正規表示式的,所以如果覺得自己對於替換很不擅長的話那麼可以好好練習一下正規表示式。

 

 

sed是一個實用性很強的文字編輯工具,由於能力所限,也只能對sed進行下簡要的介紹,大家若對其有進一步的興趣可以查詢更專業的書籍。

在sed命令中引入shell變數 http://www.linuxidc.com/Linux/2014-03/97896.htm

Linux下Shell程式設計——sed命令基本用法 http://www.linuxidc.com/Linux/2013-06/85526.htm

Unix文字處理工具之sed  http://www.linuxidc.com/Linux/2013-08/89315.htm

sed 高階用法 http://www.linuxidc.com/Linux/2014-09/106961.htm

sed命令詳解與範例 http://www.linuxidc.com/Linux/2014-11/109325.htm

Linux正規表示式sed 詳述  http://www.linuxidc.com/Linux/2015-04/116309.htm

Linux文字處理工具之sed  http://www.linuxidc.com/Linux/2015-01/111436.htm

本文永久更新連結地址http://www.linuxidc.com/Linux/2016-08/134659.htm


IT145.com E-mail:sddin#qq.com