Shell 三劍客之 sed
1. Sed 概述
1.1 Sed 是什么
Sed 全名為 Stream EDitor,顧名思義是對(duì)數(shù)據(jù)流進(jìn)行編輯操作的一個(gè)命令,它能夠遍歷文件或文件流,對(duì)讀入的輸入流可以將其先存儲(chǔ)在模式空間中,并將行號(hào)記錄在內(nèi)存中,利用模式空間中的一系列指定命令對(duì)其進(jìn)行操作,待操作完成后從模式空間輸出到 stdout,類似于在一個(gè)管道在其中對(duì)數(shù)據(jù)進(jìn)行加工,完成后從另一頭輸出,接著讀取下一行,重復(fù)往返,直至將所有標(biāo)準(zhǔn)輸入讀取處理完成。
1.2 為什么用 Sed
Sed 相較于 grep/awk,其主要功能為對(duì)文件進(jìn)行修改處理,可以對(duì)文件或標(biāo)準(zhǔn)輸入數(shù)據(jù)流進(jìn)行增刪改查等操作,尤其適用于大文件或有規(guī)律的文件,利用此工具,能夠幫助我們快捷的在編寫 Shell 腳本中得心應(yīng)手的對(duì)文件進(jìn)行操作。
2. Sed 的適用場(chǎng)景
-
超大文件處理;
-
有規(guī)律的文本,例如格式化后的日志文件等;
-
對(duì)文件進(jìn)行批量增加,替換等。
3. Sed 的處理模式
Sed 對(duì)輸入的一行數(shù)據(jù)進(jìn)行處理的模式,對(duì)整個(gè)文件進(jìn)行重復(fù)執(zhí)行此模式處理,在此說(shuō)明對(duì)輸入的一行數(shù)據(jù)處理的內(nèi)在機(jī)制如下圖所示:

-
首先讀入文件流的一行到模式空間;
-
在模式空間內(nèi),對(duì)內(nèi)容進(jìn)行模式匹配處理;
-
輸出處理后的數(shù)據(jù)內(nèi)容;
-
清空當(dāng)前模式空間;
-
讀取第二行輸入流到模式空間;
-
又開始對(duì)模式空間內(nèi)的下一行輸入數(shù)據(jù)進(jìn)行處理。
4. 語(yǔ)法詳解
sed 語(yǔ)法格式如下圖所示:

sed [option] 'address command' [file …]
sed 的語(yǔ)法格式主要分為四個(gè)字段,options 選項(xiàng),引號(hào)內(nèi)有地址定界 / 命令,以及要處理的文件,接下來(lái)讓我們?cè)敿?xì)講解每一個(gè)語(yǔ)法字段,更全面的認(rèn)識(shí) sed 這個(gè)腳本利器。
4.1 options:
選項(xiàng)為可選,利用它來(lái)為 sed 指定一些處理方式,主要的有如下:
- -n: 靜默模式,我們知道 sed 默認(rèn)處理完模式空間后將內(nèi)容輸出到標(biāo)準(zhǔn)輸出,利用這個(gè)這個(gè)參數(shù)僅顯示 script 處理后的結(jié)果,不再默認(rèn)顯示模式空間中的內(nèi)容,例如:打印 /etc/passwd 的第三行
[root@shell workspace]# sed -n '3p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
在此直接指定地址定界 3,然后 command 為 p 打印輸出,由于不想輸出 /etc/passwd 的全部?jī)?nèi)容,因此添加了 - n 選項(xiàng)。
* -e:<script>或--expression=<script> 以選項(xiàng)中指定的script來(lái)處理輸入的文本文件,可以同時(shí)執(zhí)行多個(gè)腳本;
* -f:對(duì)制定的文件直接進(jìn)行sed的command操作;
* -i:直接修改原文件,我們都知道sed默認(rèn)不對(duì)文件進(jìn)行修改,只是讀入一行到模式空間中,處理完成后輸出,此參數(shù)為也直接修改了源文件;
* -r:支持?jǐn)U展正則表達(dá)式,而不是使用默認(rèn)的基礎(chǔ)正則表達(dá)式。類比grep命令的egrep,更加快捷簡(jiǎn)潔的使用擴(kuò)展正則表達(dá)式,因?yàn)橛行┰址挥迷偈褂梅葱本€"\\"了。
4.2 address:
地址定界用來(lái)指定讀入文件的邊界或步長(zhǎng)。
startline,endline
:指定讀入文件的開始行于結(jié)束行號(hào)。/regexp/
: 利用正則表達(dá)式匹配到的行進(jìn)行處理,例如:打印 /etc/passwd 從以 root 開始到 sync 結(jié)束的內(nèi)容
[root@shell workspace]# sed -n '/^root/,/^sync/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
在此利用了匹配元字符 ^
用來(lái)匹配行首,此內(nèi)容在正則表達(dá)式中已經(jīng)進(jìn)行了詳細(xì)解釋。
/pattern1/,/pattern2/
: 第一次被 pattern1 匹配到的行開始,直到被 pattern2 匹配到的行結(jié)束,例如:打印 /etc/passwd 的第四行到第七行的內(nèi)容
[root@shell workspace]# sed -n '3,7p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
linenuber
: 直接指定行號(hào),需要處理哪一行。startline,+n
: 從那一行開始,往后 n 行結(jié)束,例如:打印 /etc/passwd 的從第三行開始往后的 2 行的內(nèi)容
[root@shell workspace]# sed -n "3,+2p" /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
startline~step
: 指定步長(zhǎng),每隔 step 步進(jìn)行處理,常用在奇偶數(shù)處理,例如:打印奇數(shù)行
seq 10 |sed -n '1~2p'
seq 來(lái)輸出以數(shù)字為內(nèi)容的 10 行,然后利用 ~2
作為步長(zhǎng)打印輸出。
4.3 command:
具體對(duì)指定的文件進(jìn)行怎樣的處理,例如對(duì)模式空間內(nèi)的內(nèi)容進(jìn)行增刪改查具體的操作。
4.3.1 增
- i:insert,在制定或匹配到的行前面添加新行內(nèi)容為 string,
i\string
,
為 /etc/passwd 中的第一行前面添加一行內(nèi)容為 "####",例如:
[root@shell workspace]# sed '1i####' /etc/passwd
####
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....
- a:append,在指定或匹配到的行后面追加新行,內(nèi)容為 string,
a\string
。
為 /etc/passwd 的第一行后面添加內(nèi)容 "aaa",例如:
[root@shell workspace]# sed '1a###' /etc/passwd
root:x:0:0:root:/root:/bin/bash
###
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
4.3.2 刪
- d:delete,刪除符合地址定界條件的的行
刪除 /etc/inittab 文件中注釋行,例如:
sed '/^#/d' /etc/inittab
直接利用元字符匹配鉚定以#
開頭的行進(jìn)行刪除操作,注意此處沒(méi)有直接修改文件,如果添加 -i
選項(xiàng),則直接對(duì)源文件進(jìn)行修改,一般需要先備份,然后操作以免誤操作原始文件。
4.3.3 改
- s:
s/pattern/string/修飾符
: 查找并替換,默認(rèn)只替換每行中第一次被模式匹配到的字符串 ,如果修飾符為 g, 則為全部替換。
替換 /etc/passwd 中的 root 為大寫,例如:
[root@shell workspace]# sed 's/root/ROOT/g' /etc/passwd
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
...
替換 /etc/inittab 文件中 "id:3:initdefault:" 一行中的數(shù)字為 5,例如:
sed 's/id:[0-9]/id:5/g' /etc/inittab
在此利用元字符匹配 [0-9] 的一個(gè)數(shù)字進(jìn)行替換為 id:5
。
4.3.4 查
- p:print,默認(rèn) sed 對(duì)模式空間內(nèi)的處理完畢后,將輸出的結(jié)果輸出在標(biāo)準(zhǔn)輸出,添加 p 命令,相當(dāng)于輸出了原文,又一次輸出了模式匹配處理后的內(nèi)容。
打印 /etc/passwd 的第三行,指定行號(hào),例如:
[root@shell workspace]# sed -n '3p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
在此直接指定地址定界 3,然后 command 為 p 打印輸出,由于不想輸出 /etc/passwd 的全部?jī)?nèi)容,因此添加了 - n 選項(xiàng)。
5. 實(shí)例
5.1 需求
目前騰訊云服務(wù)器 Ubuntu 版本用戶為 ubuntu 用戶,現(xiàn)又 1000 臺(tái)服務(wù)器需要去開啟 root 遠(yuǎn)程登錄。
5.2 思路
開啟 ubuntu 服務(wù)器的遠(yuǎn)程登錄即修改其的 /etc/ssh/sshd_config 文件的 prohibit-password 為 yes 即可,重啟 sshd 服務(wù)即可,利用腳本邏輯處理。
5.3 實(shí)現(xiàn)
核心利用 sed 代碼:
if [ ${ostype} == 'Ubuntu' ];then
sed -i 's/prohibit-password/yes/g' /etc/ssh/sshd_config
# 重啟ssh服務(wù)
service sshd restart
[ $? -eq 0] && echo "${OSTYPE} sshd 開啟成功" >>${LOG_FILE}
fi
6. 注意事項(xiàng)
- sed 中利用于正則表達(dá)式配合可以得到 1+1 大于二的效果,配合使用功能更加豐富強(qiáng)大;
- sed 常用于修改文件,如果為查詢文件可以利用 grep,因?yàn)?grep 檢索文件效率最高,如果為格式化輸出建議使用 awk;
- sed 在修改文件的時(shí)候盡可能先不要添加
-i
options,以免將源始文件修改異常難以恢復(fù)。
7. 小結(jié)
sed 的功能非常強(qiáng)大,它是我們 shell 編程中對(duì)文件修改不可或缺的利器,配合正則表達(dá)式常用來(lái)批量修改大文件,或有一定格式規(guī)律的文件,其還有很多高級(jí)功能。如果學(xué)有余力建議去 man 手冊(cè)詳細(xì)學(xué)習(xí)查看,在利用 sed 工具的時(shí)候需要時(shí)刻腦海中牢記求語(yǔ)法格式,萬(wàn)變不離其宗,遵循語(yǔ)法舉一反三能夠達(dá)到學(xué)生事半功倍的效果。