文本處理三劍客之sed

文本處理三劍客之sed


  • sed概述

  • sed使用示例

  • sed的高級應用


sed概述

sed, 作為文本三劍客之一,其定位就是一個編輯器, 而且sed是一個流式編輯器(stream editor),其主要功能是過濾和轉換文本。

sed - stream editor for filtering and transforming text

作為一個強大的文本處理功能,sed 自然能夠配合正則表達式,另外,所謂流編輯器,sed 是逐行地讀取文本,在文本行中應用指定的命令,且默認輸出到stdout; sed 擁有兩個緩沖區,活躍模式空間(active pattern space)與輔助保持空間(auxiliary hold space), 簡稱為模式空間與保持空間,且這兩個空間默認都為空。

`sed' maintains two data buffers: the active _pattern_ space, 
and theauxiliary _hold_ space. Both are initially empty.

sed的基本應用只用到模式空間就夠了,sed的高級應用需要模式空間與保持空間的想到配合。在sed

的基本應用中,sed會把當前處理的行存儲在一個臨時緩沖區,即模式空間;然后sed會在模式空間中處理文本,并且傳送到標準輸出,再接著處理下一行,如
此循環往復,直至文件末尾,這就是sed的基本工作原理。由此可風,sed在默認情況下是不修改原文件的;在sed的高級應用中,多了一個保持空間,保持
空間是與模式空間進行交互的,且以模式空間為主,保持空間為輔,sed匹配的內容最終都得經由模式空間傳輸至stdout.

常用參數

  1. -n: –quiet, –silent, 靜默模式,不輸出模式空間內容的自動打印

  2. -e: –expression=script, 多點編輯,類似于管道

  3. -f: –file=script-file, 從指定文件中讀取sed腳本

  4. -r: 支持使用擴展正則表達式

  5. -i: 原處編輯,-i.bak可同時作備份

sed地址定界

所謂sed的地址定界,就是我們對要處理的文本給出一個范圍,然后讓sed只針對此范圍去做相應的處理。

  1. 不給地址,默認全文處理

  2. 單地址:

    #:指定的行
     /pattern/:被此模式所能匹配到的每一行
  3. 地址范圍:

    #,#:從多少行到多少行
     #,+#:從第#行起至第#行+#行結束(相對地址)
     #,/part/: 從第#行開始,到第一次匹配到/part/模式結束
     /part1/,/part2/: 從第一次匹配到/part1/開始,到最后一次匹配到/part2/結束
  4. 步進: ~

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

sed編輯命令

  1. d: 刪除模式空間匹配到的行

  2. p: 顯示模式空間中的內容

  3. a \test: 在行后面追加文本,\可用空格替代;支持使用\n 實現多行追加

  4. i \test: 在行前面插入文本,\可用空格替代;支持使用\n 實現多行插入

  5. c \test: 替換為單選或多行文本,\可用空格替代

  6. w /PATH/TO/SOMEFILE: 另存為模式匹配的行到指定文件

  7. r /PATH/TO/SOMEFILE: 讀取指定文件的文本至模式空間匹配到的行后

  8. =: 為模式空間的行打印行號

  9. !: 模式空間匹配的行作反處理

  10. s///: 查找替換,支持使用其它分隔符,如s@@@, s###

替換標記:
            g: 行內全局替換
            p: 顯示替換成功的行
            w /PATH/TO/SOMEFILE:將替換成功的行保存至指定的文件中


sed使用示例

創建一個測試文件:

[root@centos7 ~#]cat f1
1
2
3
4
5
  1. 刪除f1中的空格并寫入原文件

[root@centos7 ~#]sed -i '/^$/d' f1

wKiom1erEDvSleAdAABC4VPEYmQ943.png

  1. 刪除1-3行

[root@centos7 ~#]sed '1,3d' f1
4
5
[root@centos7 ~#]
  1. 打印出第2行,并說明默認打印模式空間的意義

[root@centos7 ~#]sed -n '2p' f1   # 只打印出了第2行
2
[root@centos7 ~#][root@centos7 ~#]sed '2p' f1
1
2                               # sed 默認顯示出模式空間中的2
2                               # sed 匹配到第2行并打印出
3
4
5
  1. 給第2行后加入‘liansir’字樣,在第3行前加入‘xiaolei'字樣,替換第4行為’lvxing'

[root@centos7 ~#]nl f1 |sed -e '2a \liansir' -e '3i \xiaolei' -e '4c \lvxing' 
     1  1           # 命令n: nl - number lines of files
     2  2
liansir
xiaolei     
     3  3
lvxing     
     5  5
[root@centos7 ~#]
  1. 給f1加入空格后并顯示空格行號

[root@centos7 ~#]sed -n '/^$/=' f1

wKioL1erEYfhxMeiAAAxw1iZk_A483.png

  1. 給數字2后加'liansir'字樣,給數字3前加'xiaolei'字樣

[root@centos7 ~#]sed -e 's/2/&liansir/' -e 's/3/xiaolei&/' f1

wKioL1erJifjoTt9AAAyaxK3ZTI975.png

  1. 刪除/etc/grub2.cfg文件中所有以空白開頭的行行首的空白字符

[root@centos7 ~#]sed -r 's/^[[:space:]]+//' /etc/grub2.cfg   # 以“替換”的方式實現了“刪除”,-r 表示使用擴展正則表達式

wKioL1erJonjH9eRAAB3iSDcYtk073.png

wKiom1erJpyx_RNjAAAxw1iZk_A118.png

  1. 刪除/etc/fstab文件中所有以#開頭,后面至少跟一個空白字符的行的行首的#和空白字符

[root@centos7 ~#]sed -r 's/^#[[:space:]]*//' /etc/fstab

wKiom1erJqySxaeQAACjBTSSyu4251.png

wKioL1erJseiBuAgAACjjU_TG1s241.png

  1. 在/root/install.log每一行行首增加#號

[root@centos6 ~#]sed 's/^/#/' /root/install.log
或[root@centos6 ~#]sed -r 's/(.*)/#\1/' /root/install.log  # 后向引用,注意使用擴展正則表達式
或[root@centos6 ~#]sed -r 's/(.*)/#&/' /root/install.log

wKioL1erJuaA8zJNAACRixUhHXU596.png

  1. 處理/etc/fstab路徑,使用sed命令取出其目錄名和基名 (此題有料,眾多解法,有興趣者探索之)

取基名:下面命令的主要思路是不管前面是什么,只錨定最后一個單詞的開頭

[root@centos6 ~#]echo '/etc/fstab' |sed -r 's/(.*)\/<//'  # 注意轉義
/etc/fstab
[root@centos6 ~#]
[root@centos6 ~#]echo '/etc/fstab' |sed -r 's@(.*)/<@@'  # 不想轉義可直接換分隔符
/etc/fstab
[root@centos6 ~#]echo '/etc/fstab/' |sed -r 's@(.*)/<@@' # 當基名為一個目錄時照樣適用
/etc/fstab/
[root@centos6 ~#]

取目錄名:著眼點還是在后面的基名上,即刪除了基名

[root@centos6 ~#]echo '/etc/fstab' |sed -r 's@[^/]+/?$@@'
/etc/
[root@centos6 ~#]echo '/etc/' |sed -r 's@[^/]+/?$@@'     
/
[root@centos6 ~#]

取目錄名與基名的完美解法

[root@centos6 ~#]echo /etc/fstab |sed -r 's@(.*/)([^/]+/?)$@\1@'  # 取目錄名
/etc/
[root@centos6 ~#]echo /etc/fstab |sed -r 's@(.*/)([^/]+/?)$@\2@'  # 取基名
fstab
[root@centos6 ~#]

完美之外:

1. 涉及到/ 時則換分隔符,避免轉義,如@
2. 將目錄名與基名以分組的形式分別表示出來,表達了一個完整的路徑
3. 分別后向引用則可取得目錄名或基名,屬于通用解法
  1. 利用sed 取出ifconfig命令中本機的IPv4地址 # 先打印出本機IP所在行,然后"掐頭去尾"。

[root@centos7 ~#]ifconfig |sed -n '2p' |sed -e 's/.*inet//' -e 's/net.*//'
 10.1.253.100  
[root@centos7 ~#]
  1. 統計centos安裝光盤中Package目錄下的所有rpm文件的以.分隔倒數第二個字段的重復次數

[root@centos6 /media/CentOS_6.8_Final/Packages#]ls |sed -r 's@.*\.(.*)\.rpm$@\1@' |sort |uniq -c
      4 i686    
      919 noarch      
      1 TRANS.TBL   
      2283 x86_64
[root@centos6 /media/CentOS_6.8_Final/Packages#]
# 注意\.是轉義.

至此,我們再來了解下sed的高級應用!

sed高級編輯命令:

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

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

  3. g: 從保持空間讀取數據覆蓋至模式空間中

  4. G: 從保持空間讀取數據追加至模式空間中

  5. x: 把模式空間中的內容與保持空間的內容進行互換

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

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

  8. d: 刪除模式空間中的行

  9. D: 刪除當前模式空間開端至\n的內容(不再傳至標準輸出),放棄之后的命令,但是對剩余模式空間重新執行sed.

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.
x      Exchange the contents of the hold and pattern spaces.
n N    Read/append the next line of input into the pattern space.
d      Delete pattern space.  Start next cycle.

可見,模式空間與保持空間的交互命令有:h, H, g, G, x.其流向關系可用下圖表示:

wKioL1erJ2yjr5zhAAAhKP-QJ_c512.png

sed高級應用示例

創建一個測試文件:

[root@centos7 ~#]echo {1..5} |tr ' ' '\n' >f1
[root@centos7 ~#]cat f1
1
2
3
4
5
[root@centos7 ~#]
  1. 輸出偶數行與奇數行:

普通用法:
[root@centos7 ~#]sed -n '1~2p' f1
1
3
5
[root@centos7 ~#]sed -n '2~2p' f1
2
4
[root@centos7 ~#]
高級用法:
[root@centos7 ~#]sed 'n;d' f1   
1
3
5
[root@centos7 ~#]sed -n 'n;p' f1
2
4
[root@centos7 ~#]

高級用法解析:

~#]sed 'n;d' f1
    首先,sed讀入第一行的1到模式空間,n動作匹配到第二行中的2并覆蓋掉
    模式空間中的1,此時模式空間中僅有2,又因為d動作被刪除了,模式空間全
    空了!那怎么又輸出1了呢?這是因為sed 沒有使用-n選項,故1在被2覆蓋之
    前已被sed默認輸出,而2在模式空間卻被d給干掉了,故而屏幕上輸出了1。
    然后sed雙讀入第三行中的3,被n匹配至其下一行中的4并讀入模式空間,但
    在4覆蓋3之前sed已默認打印出3,而4卻“胎死腹中”,故屏幕雙留下了3.

~#]sed -n 'n;p' f1 
    首先,sed 讀入第一行的1到模式空間,因為n動作,又匹配到第二行中的2,
    并把2讀入模式空間覆蓋掉之前的1,模式空間中的內容輸入至stdout而得到2.
    然后,sed讀入第三行中的3到模式空間,因為n動作,匹配到其下一行中的4,
    并把4讀入模式空間并覆蓋掉之前的3并p至stdout.
  1. 倒序輸出:

[root@centos7 ~#]sed '1!G;h;$!d' f1
5
4
3
2
1
[root@centos7 ~#]

高級用法解析

~#]sed '1!G;h;$!d' f1
    這個sed命令,整體被分別;分隔為三段,我們認為他有三個動作:
    1!G;  如果不是第1行,則把保持空間中的內容追加至模式空間(保持空間默認為空)    
    h;    把模式空間中的內容覆蓋至保持空間
    $!d   如果不是最后一行則刪除

結合sed流編輯器的特點,逐行讀入,意味每讀入一行便會執行上面的三個動作;
每一行:
1. sed讀入第一行中的1到模式空間,由于不符合'1!'這個條件,則跳過G執行h;
2. h 把模式空間中的1覆蓋至保持空間;(此時模式空間中為1,保持空間中為1)
3. 1不是最后一行,符合條件'$!',刪除(此時模式空間為空,保持空間都為1)
第二行:
1. sed讀入第二中的2至模式空間,符合'1!'這個條件,從而執行G動作,G把
保持空間中的1追加至模式空間;
于是,此時模式空間中的內容為:
2
1
但保持空間是1
2. h 把模式空間中的內容覆蓋至保持空間
3. 執行 $!d(模式空間為空)

依次類推,當執行完第四步時,情況是這樣的:模式空間為空,保持空間的內容為:
4
3
2
1
第五步:
1. sed讀入第五行中的內容5至模式空間,符合'1!'這個條件,執行G動作,把
保持空間中的內容追加到模式空間
2. h 把模式空間中的內容覆蓋至保持空間
3. 第五行是最后一行,不符合'$!',跳過$!d于是,屏幕上顯示:
5
4
3
2
1

一個sed的高級命令,應得大費如此篇幅,目的就是更為深入地理解sed這個流編輯器,逐行處理文本,有兩個模式空間,一主一輔??聪聢D(圖片來自網友),就更能清楚地理解sed的工作原理了。

wKioL1erKAbClxluAAB_8W01-iY715.png

此圖僅供參考!

  1. 一鍋上了先

[root@centos7 ~#]sed '$!N;$!D' f1
4
5
[root@centos7 ~#]
[root@centos7 ~#]sed '$!d' f1  # 不是最后一行則刪除,意味著最后一行保留輸出
5
[root@centos7 ~#]
[root@centos7 ~#]sed 'G' f1   # 保留空間默認為空
1

2

3

4

5
[root@centos7 ~#]

[root@centos7 ~#]sed 'g' f1





[root@centos7 ~#]sed 'g' f1 |wc -l  # 可見輸出了5個空格
5
[root@centos7 ~#]
[root@centos7 ~#]sed '/^$/d;G' f1
1
2
3
4
5
[root@centos7 ~#]
[root@centos7 ~#]sed -n '1!G;h;$p' f1  # 看與高級應用分析與區別
5
4
3
2
1
[root@centos7 ~#]
4. 交換模式空間與保持空間的內容
[root@centos7 ~#]sed 'x' f1  # 模式空間中最后交換了一行被保留空間中第一個空白替換了

1
2
3
4
[root@centos7 ~#]

sed 的功能如此強大,掌握也非一日之功,sed可以幫助我們自動編輯一個或多個文件,簡化對文件的反復操作,編寫程序轉換等。

原創文章,作者:Liansir,如若轉載,請注明出處:http://www.www58058.com/33184

(0)
LiansirLiansir
上一篇 2016-08-12 09:02
下一篇 2016-08-12 14:45

相關推薦

  • Linux程序包管理相關

    前言 首先說說一個軟件的誕生過程: 程序員用編程語言寫文本格式的源代碼,但是計算機只能讀懂二進制文件,那么就需要將源代碼轉換成二進制格式,這個過程稱為編譯。編譯用的工具稱為編譯器,編譯器有很多種,在Linux上常用gcc這個編譯器。利用編譯器,得到二進制格式的文件(二進制程序(Windows上.exe.msi,Linux.elf)、庫文件、配置文件、幫助文件…

    Linux干貨 2018-01-04
  • linux下正則表達式的學習

    linux 下正則表達式用法總結 正則表達式作為一個模板,將某個字符模式與所搜索的字符串進行匹配。簡單的說,正則表示式就是處理字符串的方法。常用來匹配字符的元字符總結如下: Paste_Image.png 有了以上這些元字符原則上可以搜索出任務想要表達的字符,可為了更靈活使用,往往還要搭配一些次數匹配的用法 Paste_Image.png 例如:a&nbsp…

    Linux干貨 2017-06-04
  • Linux進程和計劃任務

                                                      &nbsp…

    系統運維 2016-09-21
  • shell腳本之測試命令(test、[])

    話不多說,直接開車 在編寫shell腳本中,我們經常需要判斷命令執行的正確與否,從而進行不同的操作。首先我們來介紹下條件性的執行操作符:根據退出狀態而定,命令可以有條件地運行。其中,利用echo的話方便我們對測試結果的查看。 (1)&& 代表條件性的AND THEN 可以理解為短路與:當&&前面命令為真時,執行&am…

    Linux干貨 2017-08-05
  • Linux程序包管理(rpm、yum、make)

    linux系統程序安裝的方法有rpm yum 以及make手動編譯3種方法: rpm這個機制最早由Redhat公司開發出來,后來由于實在好用,所以被很多發行版所使用作為軟件安裝的管理方式。不過由于使用RPM安裝軟件時有時會涉及到文件的依賴信,此時需要手動去逐個安裝被依賴的包操作起來十分復雜,于是yum這種線上升級的機制便出現了,它會自己主動解決各文件的依賴關…

    Linux干貨 2017-10-02
  • Linux之數組

      Linux之數組     數組介紹?數組:存儲多個元素的連續的內存空間,相當于多個變量的集合。 ?變量:存儲單個元素的內存空間?數組名和索引索引:編號從0開始,屬于數值索引注意:索引可支持使用自定義的格式,而不僅是數值格式,即為關聯索引,bash4.0版本之后開始支持。bash的數組支持稀疏格式(索引不連續)?聲明數組:de…

    Linux干貨 2016-08-25
欧美性久久久久