文本處理三劍客之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這個流編輯器,逐行處理文本,有兩個模式空間,一主一輔。看下圖(圖片來自網友),就更能清楚地理解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
下一篇 2016-08-12

相關推薦

  • Linux基礎學習總結(二)

    經過前兩周的學習,我們大家對于Linux系統和操作已經有了一定的認識。基于Linux平臺進行開發,確實要更方便和高效,我經過自己的學習消化,現在將自己的理解的幾點總結下來: Linux哲學思想的幾句話,簡潔的闡明了linux系統的特點。其中一切都是一個文件這句話特別精辟,在實際學習和操作linux系統之后,更是深刻體會到了這句話的內涵,感受頗深。它具體指明了…

    Linux干貨 2018-03-16
  • Linux常用命令說明

    個人認為把操作練習打在博客上比較愚蠢,關于操作部分我將以練習題的形式展示,每周固定練習這些基礎的題目 Linux常見命令練習 1.文本內容顯示 1.1cat: (1)顯示/root下adjtime文件內容 (2)把文件mm.txt的文件內容加上行號輸入到textfile2文件中 (3)把文件mm.txt和textfile2的文件內容加上行號(空白行不加)之后…

    Linux干貨 2016-10-29
  • 文件權限

    文件權限 文件屬性       rw-r–r–表示文件權限     Root 表示文件所有者     Root 表示文件所屬組     0 表示文件的大小 …

    Linux干貨 2016-08-11
  • 馬哥教育網絡班第21期+第四周課程作業

    1. 復制/etc/skel目錄為/home/tuser1,要求/home/tuser1及其內部文件的屬組和其它用戶均沒有任何訪問權限。 cp -r /etc/skel /home/tuser1 chmod –R 700 /home/tuser1 2. 編輯/etc/group文件,添加組hadoop。 echo &q…

    Linux干貨 2016-08-01
  • 軟件包管理詳解

      軟件包管理器 1、功能: (1)將軟件包打包成一個文件,其中包括: ①二進制程序 ②庫文件 ③配置文件 ④幫助文件 (2)生成數據庫,追中所安裝的每一個文件。 2、軟件包管理器的核心功能: (1)制作軟件包 (2)安裝、卸載、升級、查詢、校驗 3、不同發行版的不同的…

    2017-08-11
  • httpd功能配置之CGI程序

        httpd服務中有一個cgi-bin目錄,此目錄專門用于存放cgi腳本。CGI即網關通用接口,用于實現動態網頁。下面簡單編寫一個CGI腳本來進行測試此功能:     1、在/var/www/cgi-bin/目錄下創建一個腳本     2、重啟服務     3、驗證 &nb…

    Linux干貨 2016-03-11
欧美性久久久久