Sed是一款流編輯工具,用來對文本進行過濾與替換操做,特別是當你想要對幾十個配置文件作統一修改時,你會感覺到Sed的魅力!Sed經過一次僅讀取一行內容來對某些指令進行處理後輸出,因此Sed更適合於處理大數據文件。首先,Sed經過文件或管道讀取文件內容,但Sed默認並不直接修改源文件,而是將讀入的內容複製到緩衝區中,咱們稱之爲模式空間(pattern space),全部的指令操做都是在模式空間中進行的,而後Sed根據相應的指令對模式空間中的內容進行處理並輸出結果,默認輸出至標準輸出(即屏幕上)。Sed工做流程以下圖所示:正則表達式
Sed從文件中讀取數據,若是沒有輸入文件,則默認對標準輸入進程數據進行處理,腳本指令是第一個非「-」開頭的參數,具體語法格式以下。緩存
用法:sed[選項]...{腳本指令} [輸入文件]...
選項:--version 顯示sed版本
-h或--help 顯示幫助文檔
-n或--quiet或--silent 靜默輸出,默認狀況下,sed程序在全部的腳本指令執行完畢後,將自動打印模式空間中的內容,該選項能夠屏蔽自動打印app
-e script 容許多個腳本指令被執行
-f script-file 從文件中讀取腳本指令,對編寫自動腳本程序很實用
-i或-in-place 慎用,該選項將直接修改源文件
-l N 該選項指定l指令能夠輸出的行長度,l指令爲輸出非打印字符
--posix 禁用GNU sed擴展功能
-r 在腳本指令中使用擴展正則表達式
-s或--separate 默認狀況下,sed將把輸入的多個文件名做爲一個長的連續的輸入流。而GNU sed則容許把它們看成單獨的文件
-u或-unbuffered 最低限度的緩存輸入與輸出運維
Sed 經過特定的腳本指令對文件進行處理,這裏就簡單介紹幾個腳本指令操做做爲Sed程序的範例。a,append表示追加指令;i,insert表示插入指令;d,delete表示刪除指令;s,substitution表示替換指令。sed腳本指令的基本格式是:[地址]命令(有些命令僅能夠對一行操做,有些能夠對多行操做),命令也能夠用花括號進行組合,使命令序列能夠做用於同一個地址。工具
address {
command1
command2
command3
}測試
下面的test.txt爲操做樣本源文件(注意有若干空白行),介紹Sed的用法。大數據
[root@192 ~]# cat test.txt
DEVICE=ens33
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254ui
ONBOOT=yesspa
[root@192 ~]# sed '2a TYPE=Ethernet' test.txt # 第二行後追加TYPE=Ethernet命令行
[root@192 ~]# sed '3i TYPE=Ethernet' test.txt # 第三行前追加TYPE=Ethernet
[root@192 ~]# sed 's/yes/no/g' test.txt # 將樣本文件中的全部yes替換爲no
[root@192 ~]# sed '3,4d' test.txt # 刪除第3,4行的內容
[root@192 ~]# sed -e '3,4d' test.txt # 刪除第3,4行的內容
注意:這裏 sed -e 和 sed 是同樣的!同時也要注意的是,sed 後面接的動做,請務必以 '' 兩個單引號括住!
以上大多數操做指令都依據行號定位操做對象(地址),如:2a即第二行後追加。
實際工做中,可能大多數狀況你並不肯定你要操做對象(地址)的行號,這時更多的會使用正則表達式肯定操做對象(地址)。下面是使用正則表達式定位操做行的示例:
匹配到包含ONBOOT的行,並在其後添加TYPE=Ethernet:
[root@192 ~]# sed '/ONBOOT/a TYPE=Ethernet' test.txt
匹配以GATEWAY開始的行,並刪除該行:
[root@192 ~]# sed '/^GATEWAY/d' test.txt
另外,咱們的操做指令能夠寫入到腳本文件中,並經過sed的-f選項讀取,腳本文件中的註釋行是以#開始的行,若是#後面的字符爲n,則屏蔽Sed程序的自動輸出功能,等同於命令選項-n。
建立一個sed腳本,內容以下:
[root@192 ~]# cat sed.sh # 腳本內容爲匹配到空白行後,刪除該行
# This is a test sed command
/^$/d
[root@192 ~]# sed -f sed.sh test.txt # 對test.txt文件執行sed.sh腳本指令
[root@192 ~]# sed 's/yes/no/; s/static/dhcp/' test.txt # 使用分號隔開指令
[root@192 ~]# sed -e 's/yes/no/' -e 's/static/dhcp/' test.txt # 使用-e選項
[root@192 ~]# sed ' # 利用分行
> s/yes/no/
> s/static/dhcp/' test.txt
然而在命令行上輸入過長的指令是愚蠢的,這時須要使用-f選項指定sed 腳本文件,在腳本文件中能夠包含多行指令,並且也便於修改。
經過以上範例不難發現,咱們編寫的腳本指令須要指定一個地址來決定操做範圍,若是不指定,則默認對文件的全部行進行操做。如:sed 'd' test.txt將刪除test.txt的全部行,而'2d'則僅刪除第二行。Sed爲咱們提供瞭如下這些方式來肯定須要操做地址的範圍。
number 指定輸入文件的惟一行號
first~step 指定以first開始,並指定操做步長爲step,如一、2指定第一行、第三行、第五行……爲操做地址。2~5指定第二行開始,每5行匹配一次操做地址
[root@192 ~]# sed -n '1~2p' test.txt # 打印文件的奇數行
$ 匹配文件的最後一行
/regexp/ //中間包含的是正則表達式,經過正則表達式匹配操做地址。若是//中正則表達式爲空,匹配最近一次正則表達式的匹配地址
\cregexpc \c與c之間匹配擴展正則表達式,c字符可使用任意字符替代
addr1,addr2 匹配從操做地址1到操做地址2的全部行
[root@192 ~]# sed '2,8d' test.txt # 刪除2~8之間的全部行
addr1,+N 匹配地址1以及後面的N行內容
下表給出了經常使用的sed腳本指令的說明,下面分別看看每一個指令的詳細用法。
指令 | 功能 | 指令 | 功能 |
s | 替換 | d | 刪除 |
a | 追加 | i | 插入 |
c | 更改 | l | 打印(顯示非打印字符) |
y | 按字符轉換 | L | 打印(不顯示非打印字符) |
p | 打印 | r | 讀入文件內容 |
w | 保存至文件 | q | 退出 |
範例1
範例1所使用的樣本文件爲(注意有空白行):
[root@192 ~]# cat test.txt
DEVICE=ens33
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
編寫sed腳本爲:
[root@192 ~]# cat sed.sh
/.*/{
/^$/d
}
執行sed程序的結果以下:
[root@192 ~]# sed -f sed.sh test.txt
DEVICE=ens33
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.0.1
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
範例2~範例5所使用的樣本文件爲:
[root@192 ~]# cat test.txt
DEVICE=ens33
ONBOOT=yes
BOOTPROTO=static
NETMASK=255.255.255.0
GATEWAY=192.168.0.254
[root@192 ~]# sed '/static/a IPADDR=192.168.0.1' test.txt
[root@192 ~]# sed '/NETMASK/i IPADDR=192.168.0.1' test.txt
[root@192 ~]# sed '/ONBOOT/c ONBOOT=no' test.txt
[root@192 ~]# sed -n '1,2l' test.txt # 在sed腳本文件中,須要#n屏蔽自動輸出
結果以下:
DEVICE=ens33$
ONBOOT=yes$
打印(p):做用相似於l(列印),但不顯示非顯示字符,通常與-n配合使用
[root@192 ~]# sed -n '1,2p' test.txt
結果以下:
DEVICE=ens33
ONBOOT=yes
[root@192 ~]# sed '2q' test.txt
注意:sed -i 能夠直接修改文件的內容,沒必要使用管道命令或重定向! 不過,因爲這個動做會直接修改到原始的文件,因此請你千萬不要隨便拿系統配置來測試!
[root@192 ~]# sed -i 's/yes/no/' test.txt
[root@192 ~]# sed -i '$a # This is a test!' test.txt
參考自,丁明一 編著 《Linux運維之道》