文本處理三劍客之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.
常用參數
-
-n: –quiet, –silent, 靜默模式,不輸出模式空間內容的自動打印
-
-e: –expression=script, 多點編輯,類似于管道
-
-f: –file=script-file, 從指定文件中讀取sed腳本
-
-r: 支持使用擴展正則表達式
-
-i: 原處編輯,-i.bak可同時作備份
sed地址定界
所謂sed的地址定界,就是我們對要處理的文本給出一個范圍,然后讓sed只針對此范圍去做相應的處理。
-
不給地址,默認全文處理
-
單地址:
#:指定的行 /pattern/:被此模式所能匹配到的每一行
-
地址范圍:
#,#:從多少行到多少行 #,+#:從第#行起至第#行+#行結束(相對地址) #,/part/: 從第#行開始,到第一次匹配到/part/模式結束 /part1/,/part2/: 從第一次匹配到/part1/開始,到最后一次匹配到/part2/結束
-
步進: ~
1~2:奇數行
2~2: 偶數行
sed編輯命令
-
d: 刪除模式空間匹配到的行
-
p: 顯示模式空間中的內容
-
a \test: 在行后面追加文本,\可用空格替代;支持使用\n 實現多行追加
-
i \test: 在行前面插入文本,\可用空格替代;支持使用\n 實現多行插入
-
c \test: 替換為單選或多行文本,\可用空格替代
-
w /PATH/TO/SOMEFILE: 另存為模式匹配的行到指定文件
-
r /PATH/TO/SOMEFILE: 讀取指定文件的文本至模式空間匹配到的行后
-
=: 為模式空間的行打印行號
-
!: 模式空間匹配的行作反處理
-
s///: 查找替換,支持使用其它分隔符,如s@@@, s###
替換標記:
g: 行內全局替換
p: 顯示替換成功的行
w /PATH/TO/SOMEFILE:將替換成功的行保存至指定的文件中
sed使用示例
創建一個測試文件:
[root@centos7 ~#]cat f1 1 2 3 4 5
-
刪除f1中的空格并寫入原文件
[root@centos7 ~#]sed -i '/^$/d' f1
-
刪除1-3行
[root@centos7 ~#]sed '1,3d' f1 4 5 [root@centos7 ~#]
-
打印出第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
-
給第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 ~#]
-
給f1加入空格后并顯示空格行號
[root@centos7 ~#]sed -n '/^$/=' f1
-
給數字2后加'liansir'字樣,給數字3前加'xiaolei'字樣
[root@centos7 ~#]sed -e 's/2/&liansir/' -e 's/3/xiaolei&/' f1
-
刪除/etc/grub2.cfg文件中所有以空白開頭的行行首的空白字符
[root@centos7 ~#]sed -r 's/^[[:space:]]+//' /etc/grub2.cfg # 以“替換”的方式實現了“刪除”,-r 表示使用擴展正則表達式
-
刪除/etc/fstab文件中所有以#開頭,后面至少跟一個空白字符的行的行首的#和空白字符
[root@centos7 ~#]sed -r 's/^#[[:space:]]*//' /etc/fstab
-
在/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
-
處理/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. 分別后向引用則可取得目錄名或基名,屬于通用解法
-
利用sed 取出ifconfig命令中本機的IPv4地址 # 先打印出本機IP所在行,然后"掐頭去尾"。
[root@centos7 ~#]ifconfig |sed -n '2p' |sed -e 's/.*inet//' -e 's/net.*//' 10.1.253.100 [root@centos7 ~#]
-
統計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高級編輯命令:
-
h: 把模式空間中的內容覆蓋至保持空間中
-
H: 把模式空間中的內容追加至保持空間中
-
g: 從保持空間讀取數據覆蓋至模式空間中
-
G: 從保持空間讀取數據追加至模式空間中
-
x: 把模式空間中的內容與保持空間的內容進行互換
-
n: 讀取匹配到的行的下一行覆蓋至模式空間
-
N: 讀取匹配到的行的下一行追加至模式空間
-
d: 刪除模式空間中的行
-
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.其流向關系可用下圖表示:
sed高級應用示例
創建一個測試文件:
[root@centos7 ~#]echo {1..5} |tr ' ' '\n' >f1 [root@centos7 ~#]cat f1 1 2 3 4 5 [root@centos7 ~#]
-
輸出偶數行與奇數行:
普通用法: [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.
-
倒序輸出:
[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的工作原理了。
此圖僅供參考!
-
一鍋上了先
[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