grep擅長(zhǎng)查找,awk擅長(zhǎng)分析(select),sed擅長(zhǎng)批量編輯行
概述
SED的英文全稱是 Stream EDitor,它是一個(gè)簡(jiǎn)單而強(qiáng)大的文本解析轉(zhuǎn)換工具植酥,在1973-1974年期間由貝爾實(shí)驗(yàn)室的Lee E. McMahon開(kāi)發(fā),今天,它已經(jīng)運(yùn)行在所有的主流操作系統(tǒng)上了友驮。
McMahon創(chuàng)建了一個(gè)通用的行編輯器漂羊,最終變成為了SED。SED的很多語(yǔ)法和特性都借鑒了ed編輯器卸留。設(shè)計(jì)之初走越,它就已經(jīng)支持正則表達(dá)式,SED可以從文件中接受類似于管道的輸入耻瑟,也可以接受來(lái)自標(biāo)準(zhǔn)輸入流的輸入旨指。
SED由自由軟件基金組織(FSF)開(kāi)發(fā)和維護(hù)并且隨著GNU/Linux進(jìn)行分發(fā),因此喳整,通常它也稱作 GNU SED谆构。對(duì)于新手來(lái)說(shuō),SED的語(yǔ)法看起來(lái)可能有些神秘框都,但是低淡,一旦掌握了它的語(yǔ)法,你就可以只用幾行代碼去解決非常復(fù)雜的任務(wù)瞬项,這就是SED的魅力所在。
SED的典型用途
SED的用途非常廣泛何荚,例如:
文本替換
選擇性的輸出文本文件
從文本文件的某處開(kāi)始編輯
無(wú)交互式的對(duì)文本文件進(jìn)行編輯等
工作流
在本章中囱淋,我們將會(huì)探索SED是如何工作的,要想成為一個(gè)SED專家餐塘,你需要知道它的內(nèi)部實(shí)現(xiàn)妥衣。SED遵循簡(jiǎn)單的工作流:讀取,執(zhí)行和顯示戒傻,下圖描述了該工作流:
讀取: SED從輸入流(文件税手,管道或者標(biāo)準(zhǔn)輸入)中讀取一行并且存儲(chǔ)到它叫做 模式空間(pattern buffer) 的內(nèi)部緩沖區(qū)
執(zhí)行: 默認(rèn)情況下,所有的SED命令都在模式空間中順序的執(zhí)行需纳,除非指定了行的地址芦倒,否則SED命令將會(huì)在所有的行上依次執(zhí)行
顯示: 發(fā)送修改后的內(nèi)容到輸出流。在發(fā)送數(shù)據(jù)之后不翩,模式空間將會(huì)被清空兵扬。
在文件所有的內(nèi)容都被處理完成之前,上述過(guò)程將會(huì)重復(fù)執(zhí)行
需要注意的幾點(diǎn)
模式空間 (pattern buffer) 是一塊活躍的緩沖區(qū)口蝠,在sed編輯器執(zhí)行命令時(shí)它會(huì)保存待檢查的文本
默認(rèn)情況下器钟,所有的SED命令都是在模式空間中執(zhí)行,因此輸入文件并不會(huì)發(fā)生改變
還有另外一個(gè)緩沖區(qū)叫做 保持空間 (hold buffer)妙蔗,在處理模式空間中的某些行時(shí)傲霸,可以用保持空間來(lái)臨時(shí)保存一些行。在每一個(gè)循環(huán)結(jié)束的時(shí)候,SED將會(huì)移除模式空間中的內(nèi)容昙啄,但是該緩沖區(qū)中的內(nèi)容在所有的循環(huán)過(guò)程中是持久存儲(chǔ)的穆役。SED命令無(wú)法直接在該緩沖區(qū)中執(zhí)行,因此SED允許數(shù)據(jù)在 保持空間 和 模式空間之間切換
初始情況下跟衅,保持空間 和 模式空間 這兩個(gè)緩沖區(qū)都是空的
如果沒(méi)有提供輸入文件的話孵睬,SED將會(huì)從標(biāo)準(zhǔn)輸入接收請(qǐng)求
如果沒(méi)有提供地址范圍的話,默認(rèn)情況下SED將會(huì)對(duì)所有的行進(jìn)行操作
示例
讓我們創(chuàng)建一個(gè)名為 quote.txt 的文本文件伶跷,文件內(nèi)容為著名作家Paulo Coelho的一段名言
$ vi quote.txt
There is only one thing that makes a dream impossible to achieve: the fear of failure.
- Paulo Coelho, The Alchemist
為了理解SED的工作流掰读,我們首先使用SED顯示出quote.txt文件的內(nèi)容,該示例與cat
命令類似
$ sed '' quote.txt
There is only one thing that makes a dream impossible to achieve: the fear of failure.
- Paulo Coelho, The Alchemist
在上面的例子中叭莫,quote.txt是輸入的文件名稱蹈集,兩個(gè)單引號(hào)是要執(zhí)行的SED命令。
首先雇初,SED將會(huì)讀取quote.txt文件中的一行內(nèi)容存儲(chǔ)到它的模式空間中拢肆,然后會(huì)在該緩沖區(qū)中執(zhí)行SED命令。在這里靖诗,沒(méi)有提供SED命令郭怪,因此對(duì)該緩沖區(qū)沒(méi)有要執(zhí)行的操作,最后它會(huì)刪除模式空間中的內(nèi)容并且打印該內(nèi)容到標(biāo)準(zhǔn)輸出刊橘,很簡(jiǎn)單的過(guò)程鄙才,對(duì)吧?
在下面的例子中,SED會(huì)從標(biāo)準(zhǔn)輸入流接受輸入
$ sed ''
當(dāng)上述命令被執(zhí)行的時(shí)候促绵,將會(huì)產(chǎn)生下列結(jié)果
There is only one thing that makes a dream impossible to achieve: the fear of failure.
There is only one thing that makes a dream impossible to achieve: the fear of failure.
在這里攒庵,第一行內(nèi)容是通過(guò)鍵盤(pán)輸入的內(nèi)容,第二行是SED輸出的內(nèi)容败晴。
從SED會(huì)話中退出浓冒,使用組合鍵
ctrl-D (^D)
基礎(chǔ)語(yǔ)法
本章中將會(huì)介紹SED中的基本命令和它的命令行使用方法。SED可以用下列兩種方式調(diào)用:
sed [-n] [-e] 'command(s)' files
sed [-n] -f scriptfile files
第一種方式在命令行中使用單引號(hào)指定要執(zhí)行的命令尖坤,第二種方式則指定了包含SED命令的腳本文件稳懒。當(dāng)然,這兩種方法也可以同時(shí)使用慢味,SED提供了很多參數(shù)用于控制這種行為僚祷。
讓我們看看如何指定多個(gè)SED命令。SED提供了delete
命令用于刪除某些行贮缕,這里讓我們刪除第一行辙谜,第二行和第五行:
首先,使用cat
命令顯示文件內(nèi)容
$ cat books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
現(xiàn)在感昼,使用SED移除指定的行装哆,為了刪除三行,我們使用-e
選項(xiàng)指定三個(gè)獨(dú)立的命令
$ sed -e '1d' -e '2d' -e '5d' books.txt
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
6) A Game of Thrones, George R. R. Martin, 864
我們還可以將多個(gè)SED命令寫(xiě)在一個(gè)文本文件中,然后將該文件作為SED命令的參數(shù)蜕琴,SED可以對(duì)模式空間中的內(nèi)容執(zhí)行文件中的每一個(gè)命令萍桌,下面的例子描述了SED的第二種用法
首先,創(chuàng)建一個(gè)包含SED命令的文本文件凌简,為了便于理解上炎,我們使用與之前相同的SED命令
$ echo -e "1d\n2d\n5d" > commands.txt
$ cat commands.txt
1d
2d
5d
接下來(lái)構(gòu)造一個(gè)SED命令去執(zhí)行該操作
$ sed -f commands.txt books.txt
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
6) A Game of Thrones, George R. R. Martin, 864
標(biāo)準(zhǔn)選項(xiàng)
SED支持下列標(biāo)準(zhǔn)選項(xiàng):
-
-n 默認(rèn)情況下,模式空間中的內(nèi)容在處理完成后將會(huì)打印到標(biāo)準(zhǔn)輸出雏搂,該選項(xiàng)用于阻止該行為
$ sed -n '' quote.txt
-
-e 指定要執(zhí)行的命令藕施,使用該參數(shù),我們可以指定多個(gè)命令凸郑,讓我們打印每一行兩次:
$ sed -e '' -e 'p' quote.txt There is only one thing that makes a dream impossible to achieve: the fear of failure. There is only one thing that makes a dream impossible to achieve: the fear of failure.
Paulo Coelho, The Alchemist
Paulo Coelho, The Alchemist
-
-f 指定包含要執(zhí)行的命令的腳本文件
$ echo "p" > commands $ $ sed -n -f commands quote.txt There is only one thing that makes a dream impossible to achieve: the fear of failure.
- Paulo Coelho, The Alchemist
GNU選項(xiàng)
這些選項(xiàng)是GNU規(guī)范定義的裳食,可能對(duì)于某些版本的SED并不支持。
-n芙沥, --quiet, --slient:與標(biāo)準(zhǔn)的-n選項(xiàng)相同
-e script诲祸,--expression=script:與標(biāo)準(zhǔn)的-e選項(xiàng)相同
-f script-file, --file=script-file:與標(biāo)準(zhǔn)的-f選項(xiàng)相同
--follow-symlinks:如果提供該選項(xiàng)的話而昨,在編輯的文件是符號(hào)鏈接時(shí)救氯,SED將會(huì)跟隨鏈接
-i[SUFFIX],--in-place[=SUFFIX]:該選項(xiàng)用于對(duì)當(dāng)前文件進(jìn)行編輯歌憨,如果提供了SUFFIX的話径密,將會(huì)備份原始文件,否則將會(huì)覆蓋原始文件
-l N躺孝, --line-lenght=N:該選項(xiàng)用于設(shè)置行的長(zhǎng)度為N個(gè)字符
--posix:該選項(xiàng)禁用所有的GNU擴(kuò)展
-r,--regexp-extended:該選項(xiàng)將啟用擴(kuò)展的正則表達(dá)式
-u底桂, --unbuffered:指定該選項(xiàng)的時(shí)候植袍,SED將會(huì)從輸入文件中加載最少的數(shù)據(jù),并且更加頻繁的刷出到輸出緩沖區(qū)籽懦。在編輯
tail -f
命令的輸出于个,你不希望等待輸出的時(shí)候該選項(xiàng)是非常有用的。-z暮顺,--null-data:默認(rèn)情況下厅篓,SED對(duì)每一行使用換行符分割,如果提供了該選項(xiàng)的話捶码,它將使用NULL字符分割行
循環(huán)
與其它編程語(yǔ)言類似羽氮,SED提供了用于控制執(zhí)行流的循環(huán)和分支語(yǔ)句。
SED中的循環(huán)有點(diǎn)類似于goto語(yǔ)句惫恼,SED可以根據(jù)標(biāo)簽(label)跳轉(zhuǎn)到某一行繼續(xù)執(zhí)行档押,在SED中,我們可以定義如下的標(biāo)簽:
:label
:start
:end
:up
在上面的示例中,我們創(chuàng)建了四個(gè)標(biāo)簽令宿。
要跳轉(zhuǎn)到指定的標(biāo)簽叼耙,使用 b 命令后面跟著標(biāo)簽名,如果忽略標(biāo)簽名的話粒没,SED將會(huì)跳轉(zhuǎn)到SED文件的結(jié)尾筛婉。
b標(biāo)簽用于無(wú)條件的跳轉(zhuǎn)到指定的label。
為了更好地理解SED中的循環(huán)和分支癞松,讓我們創(chuàng)建一個(gè)名為books2.txt的文本文件爽撒,其中包含一些圖書(shū)的標(biāo)題和作者信息,下面的示例中會(huì)合并圖書(shū)的標(biāo)題和作者拦惋,使用逗號(hào)分隔匆浙。之后搜索所有匹配“Paulo”的行,如果匹配的話就在這一行的開(kāi)頭添加-
厕妖,否則跳轉(zhuǎn)到Print
標(biāo)簽首尼,打印出該行內(nèi)容。
$ cat books2.txt
A Storm of Swords
George R. R. Martin
The Two Towers
J. R. R. Tolkien
The Alchemist
Paulo Coelho
The Fellowship of the Ring
J. R. R. Tolkien
The Pilgrimage
Paulo Coelho
A Game of Thrones
George R. R. Martin
$ sed -n '
h;n;H;x
s/\n/, /
/Paulo/!b Print
s/^/- /
:Print
p' books2.txt
A Storm of Swords , George R. R. Martin
The Two Towers , J. R. R. Tolkien
- The Alchemist , Paulo Coelho
The Fellowship of the Ring , J. R. R. Tolkien
- The Pilgrimage , Paulo Coelho
A Game of Thrones , George R. R. Martin
乍看來(lái)上述的代碼非常神秘言秸,讓我們逐步拆解一下
第一行是
h;n;H;x
這幾個(gè)命令软能,記得上面我們提到的 保持空間 嗎?第一個(gè)h
是指將當(dāng)前模式空間中的內(nèi)容覆蓋到 保持空間中举畸,n
用于提前讀取下一行查排,并且覆蓋當(dāng)前模式空間中的這一行,H
將當(dāng)前模式空間中的內(nèi)容追加到 保持空間 中抄沮,最后的x
用于交換模式空間和保持空間中的內(nèi)容跋核。因此這里就是指每次讀取兩行放到模式空間中交給下面的命令進(jìn)行處理接下來(lái)是 s/n/, / 用于將上面的兩行內(nèi)容中的換行符替換為逗號(hào)
第三個(gè)命令在不匹配的時(shí)候跳轉(zhuǎn)到Print標(biāo)簽,否則繼續(xù)執(zhí)行第四個(gè)命令
:Print僅僅是一個(gè)標(biāo)簽名叛买,而
p
則是print命令
為了提高可讀性砂代,每一個(gè)命令都占了一行,當(dāng)然率挣,你也可以把所有命令放在一行
$ sed -n 'h;n;H;x;s/\n/, /;/Paulo/!b Print; s/^/- /; :Print;p' books2.txt
關(guān)于
h
刻伊,H
,x
命令參考官方手冊(cè) sed, a stream editor 3.6 Less Frequently-Used Commands節(jié)
分支
使用 t 命令創(chuàng)建分支椒功。只有當(dāng)前置條件成功的時(shí)候捶箱,t 命令才會(huì)跳轉(zhuǎn)到該標(biāo)簽。
t命令只有在前一個(gè)替換(s)命令執(zhí)行成功的時(shí)候才會(huì)執(zhí)行动漾。
讓我們看一些前面章節(jié)中的例子丁屎,與之前不同的是,這次我們將打印四個(gè)連字符"-"旱眯,而之前是一個(gè)悦屏。
$ sed -n '
h;n;H;x
s/\n/, /
:Loop
/Paulo/s/^/-/
/----/!t Loop
p' books2.txt
A Storm of Swords , George R. R. Martin
The Two Towers , J. R. R. Tolkien
----The Alchemist , Paulo Coelho
The Fellowship of the Ring , J. R. R. Tolkien
----The Pilgrimage , Paulo Coelho
A Game of Thrones , George R. R. Martin
在上面的例子中节沦,前面兩行與上一節(jié)中講的作用一致,第三行定義了一個(gè)Loop標(biāo)簽础爬,接下來(lái)匹配存在“Paulo”的行甫贯,如果存在則在最前面添加一個(gè)-,接下來(lái)是我們這里的重點(diǎn):
/----/!t Loop
這一行首先檢查上面添加-
之后是否滿足四個(gè)-
看蚜,如果不滿足則跳轉(zhuǎn)到Loop繼續(xù)執(zhí)行第三行叫搁,這樣不停的追加-
,最后如果改行滿足前面有四個(gè)-
才繼續(xù)往下執(zhí)行供炎。
為了提高可讀性渴逻,我們將每一個(gè)SED命令獨(dú)立一行,我們也可以在同一行中使用:
sed -n 'h;n;H;x; s/\n/, /; :Loop;/Paulo/s/^/-/; /----/!t Loop; p' books.txt
模式空間和保持空間
模式空間
對(duì)任何文件的來(lái)說(shuō)音诫,最基本的操作就是輸出它的內(nèi)容惨奕,為了實(shí)現(xiàn)該目的,在SED中可以使用print命令打印出模式空間中的內(nèi)容竭钝。
首先創(chuàng)建一個(gè)包含行號(hào)梨撞,書(shū)名,作者和頁(yè)碼數(shù)的文件香罐,在本文中我們將會(huì)使用該文件卧波,你也可以創(chuàng)建任何其它的文件,但是這里我們就創(chuàng)建一個(gè)包含以下內(nèi)容的文件
$ vi books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho,288
6) A Game of Thrones, George R. R. Martin, 864
執(zhí)行p
命令
$ sed 'p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
6) A Game of Thrones, George R. R. Martin, 864
你可能會(huì)疑惑庇茫,為什么每一行被顯示了兩次港粱?
你還記得SED的工作流嗎?默認(rèn)情況下旦签,SED將會(huì)輸出模式空間中的內(nèi)容查坪,另外,我們的命令中包含了輸出命令p
宁炫,因此每一行被打印兩次偿曙。但是不要擔(dān)心,SED提供了-n參數(shù)用于禁止自動(dòng)輸出模式空間的每一行的行為
$ sed -n 'p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
行尋址
默認(rèn)情況下淋淀,在SED中使用的命令會(huì)作用于文本數(shù)據(jù)的所有行。如果只想將命令作用于特定的行或者某些行覆醇,則需要使用 行尋址 功能朵纷。
在SED中包含兩種形式的行尋址:
以數(shù)字形式表示的行區(qū)間
以文本模式來(lái)過(guò)濾行
兩種形式都使用相同的語(yǔ)法格式
[address]command
數(shù)字方式的行尋址
在下面的示例中SED只會(huì)對(duì)第3行進(jìn)行操作
$ sed -n '3p' books.txt
3) The Alchemist, Paulo Coelho, 197
當(dāng)然,我們還可以讓SED輸出某些行永脓。在SED中使用逗號(hào),分隔輸出行號(hào)的范圍袍辞,例如下面的代碼會(huì)輸出出2-5行的內(nèi)容
$ sed -n '2,5 p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
特殊字符 $ 代表了文件的最后一行,輸出文件的最后一行
$ sed -n '$ p' books.txt
6) A Game of Thrones, George R. R. Martin, 864
也可以使用 $ 指定輸出的地址范圍常摧,下列命令輸出第三行到最后一行
$ sed -n '3,$ p' books.txt
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho,288
6) A Game of Thrones, George R. R. Martin, 864
SED還提供了另外兩種操作符用于指定地址范圍搅吁,第一個(gè)是加號(hào)(+)操作符威创,它可以與逗號(hào)(,)操作符一起使用,例如 M, +n
將會(huì)打印出從第M
行開(kāi)始的下n
行谎懦。下面的示例將會(huì)輸出第二行開(kāi)始的下面四行
$ sed -n '2,+4 p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
我們還可以使用波浪線操作符(~)指定地址范圍肚豺,它使用M~N
的形式,它告訴SED應(yīng)該處理M
行開(kāi)始的每N
行界拦。例如吸申,50~5
匹配行號(hào)50,55享甸,60截碴,65等,讓我們只輸出文件中的奇數(shù)行
$ sed -n '1~2 p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288
下面的代碼則是只輸出文件中的偶數(shù)行
$ sed -n '2~2 p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
6) A Game of Thrones, George R. R. Martin, 864
注意蛉威,如果使用的是Mac系統(tǒng)自帶的sed命令日丹,可能不支持~和+操作符◎窍樱可以使用
brew install gnu-sed --with-default-names
重新安裝GNU-SED哲虾。
使用文本模式過(guò)濾器
SED編輯器允許指定文本模式來(lái)過(guò)濾出命令要作用的行。格式如下:
/pattern/command
必須用正斜線將要指定的pattern封起來(lái)齐帚。sed編輯器會(huì)將該命令作用到包含指定文本模式的行上妒牙。
下面的示例中,將會(huì)輸出所有作者為Paulo Coelho的書(shū)籍对妄。
$ sed -n '/Paulo/ p' books.txt
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288
模式匹配也可以與數(shù)字形式的尋址同時(shí)使用湘今,在下面的示例會(huì)從第一次匹配到Alchemist
開(kāi)始輸出,直到第5行為止剪菱。
$ sed -n '/Alchemist/, 5 p' books.txt
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
使用逗號(hào)(,)操作符指定匹配多個(gè)匹配的模式摩瞎。下列的示例將會(huì)輸出Two和Pilgrimage之間的所有行
$ sed -n '/Two/, /Pilgrimage/ p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
在使用文本模式過(guò)濾器的時(shí)候,與數(shù)字方式的行尋址類似孝常,可以使用加號(hào)操作符 +旗们,它會(huì)輸出從當(dāng)前匹配位置開(kāi)始的某幾行,下面的示例會(huì)從第一次Two出現(xiàn)的位置開(kāi)始輸出接下來(lái)的4行
$ sed -n '/Two/, +4 p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
保持空間
在處理模式空間中的某些行時(shí)构灸,可以用保持空間來(lái)臨時(shí)保存一些行上渴。有5條命令可用來(lái)操作保持空間
命令
描述
h
將模式空間復(fù)制到保持空間
H
將模式空間附加到保持空間
g
將保持空間復(fù)制到模式空間
G
將保持空間附加到模式空間
x
交換模式空間和保持空間的內(nèi)容
關(guān)于保持空間這里就不在舉例了,前面再循環(huán)部分講解下面這個(gè)命令的時(shí)候我們已經(jīng)對(duì)它的使用做了說(shuō)明喜颁。
$ sed -n 'h;n;H;x;s/\n/, /;/Paulo/!b Print; s/^/- /; :Print;p' books2.txt
基本命令
本章將會(huì)講解一些常用的SED命令稠氮,主要包括DELETE
,WRITE
半开,APPEND
隔披,CHANGE
,INSERT
寂拆,TRANSLATE
奢米,QUIT
抓韩,READ
,EXECUTE
等命令鬓长。
刪除命令 d
刪除命令格式如下
[address1[,address2]]d
address1
和address2
是開(kāi)始和截止地址谒拴,它們可以是行號(hào)或者字符串匹配模式,這兩種地址都是可選的痢士。
由命令的名稱可以知道彪薛,delete 命令是用來(lái)執(zhí)行刪除操作的,并且因?yàn)镾ED是基于行的編輯器怠蹂,因此我們說(shuō)該命令是用來(lái)刪除行的善延。注意的是,該命令只會(huì)移除模式空間中的行城侧,這樣該行就不會(huì)被發(fā)送到輸出流易遣,但原始內(nèi)容不會(huì)改變。
$ sed 'd' books.txt
為什么沒(méi)有輸出任何內(nèi)容嫌佑?默認(rèn)情況下豆茫,SED將會(huì)對(duì)每一行執(zhí)行刪除操作,這就是該命令為什么沒(méi)有在標(biāo)準(zhǔn)輸出中輸出任何內(nèi)容的原因屋摇。
下列命令只移除第四行
[jerry]$ sed '4d' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
SED也接受使用逗號(hào)(,)分隔的地址范圍揩魂。我們可以構(gòu)造地址范圍去移除N1到N2行,例如炮温,下列命令將刪除2-4行
$ sed '2, 4 d' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
SED的地址范圍并不僅僅限于數(shù)字火脉,我們也可以指定模式匹配作為地址,下面的示例會(huì)移除所有作者為Paulo Coelho的書(shū)籍
$ sed '/Paulo Coelho/d' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
6) A Game of Thrones, George R. R. Martin, 864
我移除所有以Storm
和Fellowship
開(kāi)頭的行
$ sed '/Storm/,/Fellowship/d' books.txt
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
文件寫(xiě)入命令 w
SED提供了 write 命令用于將模式空間中的內(nèi)容寫(xiě)入到文件柒啤,與 delete 命令類似倦挂,下面是 write 命令的語(yǔ)法
[address1[,address2]]w file
w 指定是寫(xiě)命令, file 指的是存儲(chǔ)文件內(nèi)容的文件名担巩。使用 file 操作符的時(shí)候要小心方援,當(dāng)提供了文件名但是文件不存在的時(shí)候它會(huì)自動(dòng)創(chuàng)建,如果已經(jīng)存在的話則會(huì)覆蓋原文件的內(nèi)容涛癌。
下面的SED命令會(huì)創(chuàng)建文件books.txt的副本犯戏,在 w 和 file 之間只能有一個(gè)空格
$ sed -n 'w books.bak' books.txt
上述命令創(chuàng)建了一個(gè)名為 books.bak 的文件,驗(yàn)證一下兩個(gè)文件的內(nèi)容是否相同
$ diff books.txt books.bak
$ echo $?
一旦執(zhí)行上述的代碼拳话,你將會(huì)得到下列輸出
0
聰明的你可能已經(jīng)想到了吃媒,這不就是 cp 命令做的事情嗎候醒!確實(shí)如此棵磷,cp 命令也做了同一件事情风秤,但是SED是一個(gè)成熟的工具骨稿,使用它你可以只復(fù)制文件中的某些行到新的文件中笨鸡,如下代碼會(huì)存儲(chǔ)文件中的奇數(shù)行到另一個(gè)文件
$ sed -n '2~2 w junk.txt' books.txt
$ cat junk.txt
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
6) A Game of Thrones, George R. R. Martin, 864
假設(shè)你希望存儲(chǔ)所有獨(dú)立作者的書(shū)到單獨(dú)的文件姜钳。如果人工去做的話,肯定是非常無(wú)聊而且沒(méi)有技術(shù)含量的形耗,但是使用SED哥桥,你就有了更加聰明的方法去實(shí)現(xiàn)
$ sed -n -e '/Martin/ w Martin.txt' -e '/Paulo/ w Paulo.txt' -e '/Tolkien/ w Tolkien.txt' books.txt
$ cat Martin.txt
1) A Storm of Swords, George R. R. Martin, 1216
6) A Game of Thrones, George R. R. Martin, 864
$ cat Paulo.txt
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288
$ cat Tolkien.txt
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
追加命令 a
文本追加命令語(yǔ)法:
[address]a\
Append text
在第四行之后追加一本新書(shū):
$ sed '4 a 7) Adultry, Paulo Coelho, 234' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
7) Adultry, Paulo Coelho, 234
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
在命令部分,4指的是行號(hào)激涤,a
是append命令拟糕,剩余部分為要追加的文本。
在文件的結(jié)尾插入一行文本倦踢,使用 $ 作為地址
$ sed '$ a 7) Adultry, Paulo Coelho, 234' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
7) Adultry, Paulo Coelho, 234
除了行號(hào)送滞,我們也可以使用文本模式指定地址,例如辱挥,在匹配 The Alchemist
的行之后追加文本
$ sed '/The Alchemist/ a 7) Adultry, Paulo Coelho, 234' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
7) Adultry, Paulo Coelho, 234
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
行替換命令 c
SED通過(guò) c 提供了 change 和 replace 命令犁嗅,該命令幫助我們使用新文本替換已經(jīng)存在的行,當(dāng)提供行的地址范圍時(shí)晤碘,所有的行都被作為一組被替換為單行文本褂微,下面是該命令的語(yǔ)法
[address1[,address2]]c\
Replace text
比如,替換文本中的第三行為新的內(nèi)容
$ sed '3 c 3) Adultry, Paulo Coelho, 324' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) Adultry, Paulo Coelho, 324
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
SED也接受模式作為地址
$ sed '/The Alchemist/ c 3) Adultry, Paulo Coelho, 324' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) Adultry, Paulo Coelho, 324
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
多行替換也是支持的园爷,下面的命令實(shí)現(xiàn)了將第4-6行內(nèi)容替換為單行
$ sed '4, 6 c 4) Adultry, Paulo Coelho, 324' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) Adultry, Paulo Coelho, 324
插入命令 i
插入命令與追加命令類似宠蚂,唯一的區(qū)別是插入命令是在匹配的位置前插入新的一行。
[address]i\
Insert text
下面的命令會(huì)在第四行前插入新的一行
$ sed '4 i 7) Adultry, Paulo Coelho, 324' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
7) Adultry, Paulo Coelho, 324
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
轉(zhuǎn)換命令 y
轉(zhuǎn)換(Translate)命令 y 是唯一可以處理單個(gè)字符的sed編輯器命令童社。轉(zhuǎn)換命令格式 如下
[address]y/inchars/outchars/
轉(zhuǎn)換命令會(huì)對(duì)inchars和outchars值進(jìn)行一對(duì)一的映射求厕。inchars中的第一個(gè)字符會(huì)被轉(zhuǎn)換為outchars中的第一個(gè)字符,第二個(gè)字符會(huì)被轉(zhuǎn)換成outchars中的第二個(gè)字符叠洗。這個(gè)映射過(guò)程會(huì)一直持續(xù)到處理完指定字符甘改。如果inchars和outchars的長(zhǎng)度不同,則sed編輯器會(huì)產(chǎn)生一 條錯(cuò)誤消息灭抑。
$ echo "1 5 15 20" | sed 'y/151520/IVXVXX/'
I V IV XX
輸出隱藏字符命令 l
你能通過(guò)直接觀察區(qū)分出單詞是通過(guò)空格還是tab進(jìn)行分隔的嗎十艾?顯然是不能的,但是SED可以為你做到這點(diǎn)腾节。使用l
命令(英文字母L的小寫(xiě))可以顯示文本中的隱藏字符(例如t
或者$
字符)忘嫉。
[address1[,address2]]l
[address1[,address2]]l [len]
為了測(cè)試該命令,我們首先將books.txt中的空格替換為tab案腺。
$ sed 's/ /\t/g' books.txt > junk.txt
接下來(lái)執(zhí)行l
命令
$ sed -n 'l' junk.txt
1)\tStorm\tof\tSwords,\tGeorge\tR.\tR.\tMartin,\t1216\t$
2)\tThe\tTwo\tTowers,\tJ.\tR.\tR.\tTolkien,\t352\t$
3)\tThe\tAlchemist,\tPaulo\tCoelho,\t197\t$
4)\tThe\tFellowship\tof\tthe\tRing,\tJ.\tR.\tR.\tTolkien,\t432\t$
5)\tThe\tPilgrimage,\tPaulo\tCoelho,\t288\t$
6)\tA\tGame\tof\tThrones,\tGeorge\tR.\tR.\tMartin,\t864$
使用l
命令的時(shí)候庆冕,一個(gè)很有趣的特性是我們可以使用它來(lái)實(shí)現(xiàn)文本按照指定的寬度換行。
$ sed -n 'l 25' books.txt
1) Storm of Swords, Geor\
ge R. R. Martin, 1216 $
2) The Two Towers, J. R.\
R. Tolkien, 352 $
3) The Alchemist, Paulo \
Coelho, 197 $
4) The Fellowship of the\
Ring, J. R. R. Tolkien,\
432 $
5) The Pilgrimage, Paulo\
Coelho, 288 $
6) A Game of Thrones, Ge\
orge R. R. Martin, 864$
上面的示例中在l
命令后跟了一個(gè)數(shù)字25劈榨,它告訴SED按照每行25個(gè)字符進(jìn)行換行访递,如果指定這個(gè)數(shù)字為0的話,則只有在存在換行符的情況下才進(jìn)行換行同辣。
l
命令是GNU-SED的一部分拷姿,其它的一些變體中可能無(wú)法使用該命令惭载。
退出命令 q
在SED中,可以使用Quit
命令退出當(dāng)前的執(zhí)行流
[address]q
[address]q [value]
需要注意的是响巢,q
命令不支持地址范圍描滔,只支持單個(gè)地址匹配。默認(rèn)情況下SED會(huì)按照讀取踪古、執(zhí)行含长、重復(fù)的工作流執(zhí)行,但當(dāng)它遇到q
命令的時(shí)候伏穆,它會(huì)退出當(dāng)前的執(zhí)行流拘泞。
$ sed '3 q' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
$ sed '/The Alchemist/ q' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
q
命令也支持提供一個(gè)value,這個(gè)value將作為程序的返回代碼返回
$ sed '/The Alchemist/ q 100' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
$ echo $?
100
文件讀取命令 r
在SED中枕扫,我們可以讓SED使用Read命令從外部文件中讀取內(nèi)容并且在滿足條件的時(shí)候顯示出來(lái)田弥。
[address]r file
需要注意的是,r
命令和文件名之間必須只有一個(gè)空格铡原。
下面的示例會(huì)打開(kāi)junk.txt文件偷厦,將其內(nèi)容插入到books.txt文件的第三行之后
$ echo "This is junk text." > junk.txt
$ sed '3 r junk.txt' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
This is junk text.
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
r
命令也支持地址范圍,例如3, 5 r junk.txt會(huì)在第三行燕刻,第四行只泼,第五行后面分別插入junk.txt的內(nèi)容
執(zhí)行外部命令 e
如果你看過(guò)三十分鐘學(xué)會(huì)AWK一文,你可能已經(jīng)知道了在AWK中可以執(zhí)行外部的命令卵洗,那么在SED中我們是否也可以這樣做请唱?
答案是肯定的,在SED中过蹂,我們可以使用e
命令執(zhí)行外部命令
[address1[,address2]]e [command]
下面的命令會(huì)在第三行之前執(zhí)行date命令
$ sed '3 e date' books.txt
1) Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
2016年11月29日 星期二 22時(shí)46分14秒 CST
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
另一個(gè)示例
$ sed '3,5 e who' books.txt
1) Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
mylxsw console Nov 29 19:30
mylxsw ttys000 Nov 29 22:45
3) The Alchemist, Paulo Coelho, 197
mylxsw console Nov 29 19:30
mylxsw ttys000 Nov 29 22:45
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
mylxsw console Nov 29 19:30
mylxsw ttys000 Nov 29 22:45
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
如果你仔細(xì)觀察e
命令的語(yǔ)法十绑,你會(huì)發(fā)現(xiàn)其實(shí)它的command參數(shù)是可選的。在沒(méi)有提供外部命令的時(shí)候酷勺,SED會(huì)將模式空間中的內(nèi)容作為要執(zhí)行的命令本橙。
$ echo -e "date\ncal\nuname" > commands.txt
$ cat commands.txt
date
cal
uname
$ sed 'e' commands.txt
2016年11月29日 星期二 22時(shí)50分30秒 CST
十一月 2016
日 一 二 三 四 五 六
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Darwin
排除命令 !
感嘆號(hào)命令(!)用來(lái)排除命令,也就是讓原本會(huì)起作用的命令不起作用脆诉。
$ sed -n '/Paulo/p' books.txt
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288
$ sed -n '/Paulo/!p' books.txt
1) Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
6) A Game of Thrones, George R. R. Martin, 864
如上例所示甚亭,p
命令原先是只輸出匹配Paulo的行,添加!
之后击胜,變成了只輸出不匹配Paulo的行亏狰。
$ sed -n '1!G; h; $p' books.txt
6) A Game of Thrones, George R. R. Martin, 864
5) The Pilgrimage, Paulo Coelho, 288
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
3) The Alchemist, Paulo Coelho, 197
2) The Two Towers, J. R. R. Tolkien, 352
1) Storm of Swords, George R. R. Martin, 1216
上面的命令實(shí)現(xiàn)了類似tac
命令類似的輸出,將文本內(nèi)容倒序輸出偶摔∠就伲看起來(lái)有些晦澀難懂,分解一下卻十分簡(jiǎn)單:
1!G 這句的意思是出了第一行之外,處理每一行的時(shí)候都將保持空間中的內(nèi)容追加到模式空間(正序->倒序)
h 將模式空間中的內(nèi)容復(fù)制到保持空間以備下一行匹配的時(shí)候追加到下一行的后面
$p 如果匹配到最后一行的話則輸出模式空間中的內(nèi)容
上述步驟不斷重復(fù)直到文本結(jié)束剛好將文件內(nèi)容翻轉(zhuǎn)了一次
多行命令
在使用sed編輯器的基礎(chǔ)命令時(shí)策州,你可能注意到了一個(gè)局限嘲叔。所有的sed編輯器命令都是針對(duì)單行數(shù)據(jù)執(zhí)行操作的。在sed編輯器讀取數(shù)據(jù)流時(shí)抽活,它會(huì)基于換行符的位置將數(shù)據(jù)分成行。sed編輯器根據(jù)定義好的腳本命令一次處理一行數(shù)據(jù)锰什,然后移到下一行重復(fù)這個(gè)過(guò)程下硕。
幸運(yùn)的是,sed編輯器的設(shè)計(jì)人員已經(jīng)考慮到了這種情況汁胆,并設(shè)計(jì)了對(duì)應(yīng)的解決方案梭姓。sed編輯器包含了三個(gè)可用來(lái)處理多行文本的特殊命令。
N:將數(shù)據(jù)流中的下一行加進(jìn)來(lái)創(chuàng)建一個(gè)多行組來(lái)處理
D:刪除多行組中的一行
P:打印多行組中的一行
N - 加載下一行
默認(rèn)情況下嫩码,SED是基于單行進(jìn)行操作的誉尖,有些情況下我們可能需要使用多行進(jìn)行編輯,啟用多行編輯使用N
命令铸题,與n
不同的是铡恕,N
并不會(huì)清除、輸出模式空間的內(nèi)容丢间,而是采用了追加模式探熔。
[address1[,address2]]N
下面的示例將會(huì)把books2.txt中的標(biāo)題和作者放到同一行展示,并且使用逗號(hào)進(jìn)行分隔
$ sed 'N; s/\n/,/g' books2.txt
A Storm of Swords ,George R. R. Martin
The Two Towers ,J. R. R. Tolkien
The Alchemist ,Paulo Coelho
The Fellowship of the Ring ,J. R. R. Tolkien
The Pilgrimage ,Paulo Coelho
A Game of Thrones ,George R. R. Martin
D - 刪除多行中的一行
sed編輯器提供了多行刪除命令D烘挫,它只刪除模式空間中的第一行诀艰。該命令會(huì)刪除到換行符(含 換行符)為止的所有字符。
$ echo -e '\nThis is the header line.\nThis is a data line.\n\nThis is the last line.' | sed '/^$/{N; /header/D}'
This is the header line.
This is a data line.
This is the last line.
P - 輸出多行中的一行
P
命令用于輸出N
命令創(chuàng)建的多行文本的模式空間中的第一行饮六。
[address1[,address2]]P
例如下面的命令只輸出了圖書(shū)的標(biāo)題
$ sed -n 'N;P' books2.txt
A Storm of Swords
The Two Towers
The Alchemist
The Fellowship of the Ring
The Pilgrimage
A Game of Thrones
其它命令
n - 單行next
小寫(xiě)的n命令會(huì)告訴sed編輯器移動(dòng)到數(shù)據(jù)流中的下一文本行其垄,并且覆蓋當(dāng)前模式空間中的行。
$ cat data1.txt
This is the header line.
This is a data line.
This is the last line.
$ sed '/header/{n ; d}' data1.txt
This is the header line.
This is a data line.
This is the last line.
上面的命令中卤橄,首先會(huì)匹配包含header的行绿满,之后將移動(dòng)到數(shù)據(jù)流的下一行,這里是一個(gè)空行窟扑,然后執(zhí)行d
命令對(duì)改行進(jìn)行刪除棒口,所有就看到了這樣的結(jié)果:第一個(gè)空行被刪除掉了。
v - SED版本檢查
v
命令用于檢查SED的版本辜膝,如果版本大于參數(shù)中的版本則正常執(zhí)行无牵,否則失敗
[address1[,address2]]v [version]
例如
$ sed --version
sed (GNU sed) 4.2.2
$ sed 'v 4.2.3' books.txt
sed: -e expression #1, char 7: expected newer version of sed
$ sed 'v 4.2.2' books.txt
1) Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
特殊字符
在SED中提供了兩個(gè)可以用作命令的特殊字符:= 和 & 。
=
命令
=
命令用于輸出行號(hào)厂抖,語(yǔ)法格式為
[/pattern/]=
[address1[,address2]]=
例如為每一行輸出行號(hào)
$ sed '=' books2.txt
1
A Storm of Swords
2
George R. R. Martin
...
只為1-4行輸出行號(hào)
$ sed '1, 4=' books2.txt
1
A Storm of Swords
2
George R. R. Martin
3
The Two Towers
4
J. R. R. Tolkien
The Alchemist
Paulo Coelho
The Fellowship of the Ring
J. R. R. Tolkien
The Pilgrimage
Paulo Coelho
A Game of Thrones
George R. R. Martin
匹配Paulo的行輸出行號(hào)
$ sed '/Paulo/ =' books2.txt
A Storm of Swords
George R. R. Martin
The Two Towers
J. R. R. Tolkien
The Alchemist
6
Paulo Coelho
The Fellowship of the Ring
J. R. R. Tolkien
The Pilgrimage
10
Paulo Coelho
A Game of Thrones
George R. R. Martin
最后一行輸出行號(hào)茎毁,這個(gè)命令比較有意思了,可以用于輸出文件總共有多少行
$ sed -n '$ =' books2.txt
12
&
命令
特殊字符&
用于存儲(chǔ)匹配模式的內(nèi)容,通常與替換命令s
一起使用七蜘。
$ sed 's/[[:digit:]]/Book number &/' books.txt
Book number 1) Storm of Swords, George R. R. Martin, 1216
Book number 2) The Two Towers, J. R. R. Tolkien, 352
Book number 3) The Alchemist, Paulo Coelho, 197
Book number 4) The Fellowship of the Ring, J. R. R. Tolkien, 432
Book number 5) The Pilgrimage, Paulo Coelho, 288
Book number 6) A Game of Thrones, George R. R. Martin, 864
上述命令用于匹配每一行第一個(gè)數(shù)字谭溉,在其前面添加 Book number 。而下面這個(gè)命令則匹配最后一個(gè)數(shù)字橡卤,并修改為Pages =
扮念。其中[[:digit:]]* *$
可能比較費(fèi)解,這一部分其實(shí)是:匹配0個(gè)或多個(gè)數(shù)字+0個(gè)或多個(gè)空格+行尾碧库。
sed 's/[[:digit:]]* *$/Pages = &/' books.txt
1) Storm of Swords, George R. R. Martin, Pages = 1216
2) The Two Towers, J. R. R. Tolkien, Pages = 352
3) The Alchemist, Paulo Coelho, Pages = 197
4) The Fellowship of the Ring, J. R. R. Tolkien, Pages = 432
5) The Pilgrimage, Paulo Coelho, Pages = 288
6) A Game of Thrones, George R. R. Martin, Pages = 864
字符串
替換命令 s
文本替換命令非常常見(jiàn)柜与,其格式如下
[address1[,address2]]s/pattern/replacement/[flags]
在前面我們使用的books.txt文件中,我們使用逗號(hào)“,”分隔每一列嵌灰,下面的示例中弄匕,我們會(huì)使用替換命令將其替換為管道符“|”:
$ sed 's/,/ |/' books.txt
1) Storm of Swords | George R. R. Martin, 1216
2) The Two Towers | J. R. R. Tolkien, 352
3) The Alchemist | Paulo Coelho, 197
4) The Fellowship of the Ring | J. R. R. Tolkien, 432
5) The Pilgrimage | Paulo Coelho, 288
6) A Game of Thrones | George R. R. Martin, 864
是不是覺(jué)得哪里不對(duì)?相信你已經(jīng)發(fā)現(xiàn)沽瞭,每一行的第二個(gè)逗號(hào)都沒(méi)有被替換迁匠,只有第一個(gè)被替換了,確實(shí)如此驹溃,在SED中城丧,使用替換命令的時(shí)候默認(rèn)只會(huì)對(duì)第一個(gè)匹配的位置進(jìn)行替換。使用g
選項(xiàng)告訴SED對(duì)所有內(nèi)容進(jìn)行替換:
$ sed 's/,/ | /g' books.txt
1) Storm of Swords | George R. R. Martin | 1216
2) The Two Towers | J. R. R. Tolkien | 352
3) The Alchemist | Paulo Coelho | 197
4) The Fellowship of the Ring | J. R. R. Tolkien | 432
5) The Pilgrimage | Paulo Coelho | 288
6) A Game of Thrones | George R. R. Martin | 864
如果對(duì)匹配模式(或地址范圍)的行進(jìn)行替換豌鹤,則只需要在
s
命令前添加地址即可芙贫。比如只替換匹配The Pilgrimage的行:sed '/The Pilgrimage/ s/,/ | /g' books.txt
還有一些其它的選項(xiàng),這里就簡(jiǎn)單的描述一下傍药,不在展開(kāi)講解
數(shù)字n: 只替換第n次匹配磺平,比如
sed 's/,/ | /2' books.txt
,只替換每行中第二個(gè)逗號(hào)p:只輸出改變的行拐辽,比如
sed -n 's/Paulo Coelho/PAULO COELHO/p' books.txt
w:存儲(chǔ)改變的行到文件拣挪,比如
sed -n 's/Paulo Coelho/PAULO COELHO/w junk.txt' books.txt
i:匹配時(shí)忽略大小寫(xiě),比如
sed -n 's/pAuLo CoElHo/PAULO COELHO/pi' books.txt
在執(zhí)行替換操作的時(shí)候俱诸,如果要替換的內(nèi)容中包含/
菠劝,這個(gè)時(shí)候怎么辦?很簡(jiǎn)單睁搭,添加轉(zhuǎn)義操作符赶诊。
$ echo "/bin/sed" | sed 's/\/bin\/sed/\/home\/mylxsw\/src\/sed\/sed-4.2.2\/sed/'
/home/mylxsw/src/sed/sed-4.2.2/sed
上面的命令中,我們使用`對(duì)
/進(jìn)行了轉(zhuǎn)義园骆,不過(guò)表達(dá)式已經(jīng)看起來(lái)非常難看了舔痪,在SED中還可以使用
|,
@锌唾,
^锄码,
!`作為命令的分隔符夺英,所以,下面的幾個(gè)命令和上面的是等價(jià)的
echo "/bin/sed" | sed 's|/bin/sed|/mylxsw/mylxsw/src/sed/sed-4.2.2/sed|'
echo "/bin/sed" | sed 's@/bin/sed@/home/mylxsw/src/sed/sed-4.2.2/sed@'
echo "/bin/sed" | sed 's^/bin/sed^/home/mylxsw/src/sed/sed-4.2.2/sed^'
echo "/bin/sed" | sed 's!/bin/sed!/home/mylxsw/src/sed/sed-4.2.2/sed!'
匹配子字符串
前面我們學(xué)習(xí)了替換命令的用法滋捶,現(xiàn)在讓我們看看如何獲取匹配文本中的某個(gè)子串痛悯。
在SED中,使用(
和)
對(duì)匹配的內(nèi)容進(jìn)行分組重窟,使用N
的方式進(jìn)行引用载萌。請(qǐng)看下面示例
$ echo "Three One Two" | sed 's|\(\w\+\) \(\w\+\) \(\w\+\)|\2 \3 \1|'
One Two Three
我們輸出了Three,One巡扇,Two三個(gè)單詞扭仁,在SED的替換規(guī)則中,使用空格分隔了三小段正則表達(dá)式(w+)
來(lái)匹配每一個(gè)單詞霎迫,后面使用1
,帘靡,2
知给,3
分別引用它們的值。
管理模式
前面已經(jīng)講解過(guò)模式空間和保持空間的用法描姚,在本節(jié)中我們將會(huì)繼續(xù)探索它們的用法涩赢。
本部分內(nèi)容暫未更新,請(qǐng)關(guān)注程序猿成長(zhǎng)計(jì)劃 項(xiàng)目轩勘,我將最先在Github的這個(gè)倉(cāng)庫(kù)中更新最新內(nèi)容筒扒。
正則表達(dá)式
這一部分就是標(biāo)準(zhǔn)正則表達(dá)式的一些特殊字符以元字符,比較熟悉的請(qǐng)略過(guò)绊寻。
標(biāo)準(zhǔn)正則表達(dá)式
^
匹配行的開(kāi)始花墩。
$ sed -n '/^The/ p' books2.txt
The Two Towers, J. R. R. Tolkien
The Alchemist, Paulo Coelho
The Fellowship of the Ring, J. R. R. Tolkien
The Pilgrimage, Paulo Coelho
$
匹配行的結(jié)尾
$ sed -n '/Coelho$/ p' books2.txt
The Alchemist, Paulo Coelho
The Pilgrimage, Paulo Coelho
.
匹配單個(gè)字符(除行尾)
$ echo -e "cat\nbat\nrat\nmat\nbatting\nrats\nmats" | sed -n '/^..t$/p'
cat
bat
rat
mat
[]
匹配字符集
$ echo -e "Call\nTall\nBall" | sed -n '/[CT]all/ p'
Call
Tall
[^]
排除字符集
$ echo -e "Call\nTall\nBall" | sed -n '/[^CT]all/ p'
Ball
[-]
字符范圍。
$ echo -e "Call\nTall\nBall" | sed -n '/[C-Z]all/ p'
Call
Tall
? 澄步,\+ 冰蘑,*
分別對(duì)應(yīng)0次到1次,一次到多次村缸,0次到多次匹配祠肥。
{n} ,{n,} 梯皿,{m, n}
精確匹配N次仇箱,至少匹配N次,匹配M-N次
|
或操作东羹。
$ echo -e "str1\nstr2\nstr3\nstr4" | sed -n '/str\(1\|3\)/ p'
str1
str3
POSIX兼容的正則
主要包含[:alnum:]
剂桥,[:alpha:]
,[:blank:]
属提,[:digit:]
渊额,[:lower:]
,[:upper:]
,[:punct:]
旬迹,[:space:]
火惊,這些基本都見(jiàn)名之意,不在贅述奔垦。
元字符
s
匹配單個(gè)空白內(nèi)容
$ echo -e "Line\t1\nLine2" | sed -n '/Line\s/ p'
Line 1
S
匹配單個(gè)非空白內(nèi)容屹耐。
w , W
單個(gè)單詞椿猎、非單詞惶岭。
常用代碼段
Cat命令
模擬cat
命令比較簡(jiǎn)單,有下面兩種方式
$ sed '' books.txt
1) Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
$ sed -n 'p' books.txt
1) Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
移除空行
$ echo -e "Line #1\n\n\nLine #2" | sed '/^$/d'
Line #1
Line #2
刪除連續(xù)空行
$ echo -e "Line #1\n\n\nLine #2" | sed '/./,/^$/!d'
Line #1
Line #2
刪除開(kāi)頭的空行
$ echo -e "\nLine #1\n\nLine #2" | sed '/./,$!d'
Line #1
Line #2
刪除結(jié)尾的空行
$ echo -e "\nLine #1\nLine #2\n\n" | sed ':start /^\n*$/{$d; N; b start }'
Line #1
Line #2
過(guò)濾所有的html標(biāo)簽
$ cat html.txt
<html>
<head>
<title>This is the page title</title>
</head>
<body>
<p> This is the <b>first</b> line in the Web page.
This should provide some <i>useful</i> information to use in our sed script.
</body>
</html>
$ sed 's/<[^>]*>//g ; /^$/d' html.txt
This is the page title
This is the first line in the Web page.
This should provide some useful information to use in our sed script.
從C++程序中移除注釋
有下面這樣一個(gè)cpp文件
$ cat hello.cpp
#include <iostream>
using namespace std;
int main(void)
{
// Displays message on stdout.
cout >> "Hello, World !!!" >> endl;
return 0; // Return success.
}
執(zhí)行下面的命令可以移除注釋
$ sed 's|//.*||g' hello.cpp
#include <iostream>
using namespace std;
int main(void)
{
cout >> "Hello, World !!!" >> endl;
return 0;
}
為某些行添加注釋
$ sed '3,5 s/^/#/' hello.sh
#!/bin/bash
#pwd
#hostname
#uname -a
who
who -r
lsb_release -a
實(shí)現(xiàn)Wc -l命令
wc -l
命令用于統(tǒng)計(jì)文件中的行數(shù)犯眠,使用SED也可以模擬該命令
$ wc -l hello.cpp
9 hello.cpp
$ sed -n '$ =' hello.cpp
9
模擬實(shí)現(xiàn)head
命令
head
命令用于輸出文件中的前10行內(nèi)容按灶。
$ head books2.txt
A Storm of Swords
George R. R. Martin
The Two Towers
J. R. R. Tolkien
The Alchemist
Paulo Coelho
The Fellowship of the Ring
J. R. R. Tolkien
The Pilgrimage
Paulo Coelho
使用SED中的sed '10 q'
可以模擬它的實(shí)現(xiàn)
$ sed '10 q' books.txt
A Storm of Swords
George R. R. Martin
The Two Towers
J. R. R. Tolkien
The Alchemist
Paulo Coelho
The Fellowship of the Ring
J. R. R. Tolkien
The Pilgrimage
Paulo Coelho
模擬tail -1
命令
tail -1
輸出文件的最后一行。
$ cat test.txt
Line #1
Line #2
$ tail -1 test.txt
Line #2
$ sed $ sed -n '$p' test.txt
Line #2
模擬Dos2unix
命令
在DOS環(huán)境中筐咧,換行符是使用CR/LF兩個(gè)字符一起表示的鸯旁,下面命令模擬了dos2unix
命令轉(zhuǎn)換這些換行符為UNIX換行符。
在GNU/Linux環(huán)境中量蕊,CR/LF通常使用"^M"(不是簡(jiǎn)單的兩個(gè)符號(hào)組合铺罢,請(qǐng)使用快捷鍵Ctrl+v,Ctrl+m輸入)進(jìn)行表示。
$ echo -e "Line #1\r\nLine #2\r" > test.txt
$ file test.txt
test.txt: ASCII text, with CRLF line terminators
$ sed 's/\r$//' test.txt > new.txt
$ file new.txt
new.txt: ASCII text
$ cat -vte new.txt
Line #1$
Line #2$
模擬Unix2dos
命令
$ file new.txt
new.txt: ASCII text
$ sed 's/$/\r/' new.txt > new2.txt
$ file new2.txt
new2.txt: ASCII text, with CRLF line terminators
$ cat -vte new2.txt
Line #1^M$
Line #2^M$
模擬cat -E
命令
cat -E
命令會(huì)在每一行的行尾輸出一個(gè)$符號(hào)残炮。
$ echo -e "Line #1\nLine #2" | cat -E
Line #1$
Line #2$
$ echo -e "Line #1\nLine #2" | sed 's|$|&$|'
Line #1$
Line #2$
注意韭赘,在Mac下不支持
cat -E
,可以直接使用sed代替
模擬cat -ET
命令
cat -ET
命令不僅對(duì)每一行的行尾添加$势就,還會(huì)將每一行中的TAB顯示為^I泉瞻。
$ echo -e "Line #1\tLine #2" | cat -ET
Line #1^ILine #2$
$ echo -e "Line #1\tLine #2" | sed -n 'l' | sed 'y/\\t/^I/'
Line #1^ILine #2$
模擬nl
命令
命令nl
可以為輸入內(nèi)容的每一行添加行號(hào),記得之前介紹的=
操作符吧苞冯,在SED中我們可以用它來(lái)實(shí)現(xiàn)與nl
命令類似的功能瓦灶。
$ echo -e "Line #1\nLine #2" |nl
1 Line #1
2 Line #2
$ echo -e "Line #1\nLine #2" | sed = | sed 'N;s/\n/\t/'
1 Line #1
2 Line #2
上面的SED命令使用了兩次,第一次使用=
操作符為每一行輸出行號(hào)抱完,注意這個(gè)行號(hào)是獨(dú)占一行的贼陶,因此使用管道符連接了第二個(gè)SED命令,每次讀取兩行巧娱,將換行符替換為T(mén)ab碉怔,這樣就模擬出了nl
命令的效果。
模擬cp
命令
$ sed -n 'w dup.txt' data.txt
$ diff data.txt dup.txt
$ echo $?
0
模擬expand
命令
expand
命令會(huì)轉(zhuǎn)換輸入中的TAB為空格禁添,在SED中也可以模擬它
$ echo -e "One\tTwo\tThree" > test.txt
$ expand test.txt > expand.txt
$ sed 's/\t/ /g' test.txt > new.txt
$ diff new.txt expand.txt
$ echo $?
0
模擬tee
命令
tee
命令會(huì)將數(shù)據(jù)輸出到標(biāo)準(zhǔn)輸出的同時(shí)寫(xiě)入文件撮胧。
$ echo -e "Line #1\nLine #2" | tee test.txt
Line #1
Line #2
在SED中,實(shí)現(xiàn)該命令非常簡(jiǎn)單
$ sed -n 'p; w new.txt' test.txt
One Two Three
模擬cat -s
命令
cat -s
命令會(huì)將輸入文件中的多行空格合并為一行老翘。
$ echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | cat -s
Line #1
Line #2
Line #3
在SED中實(shí)現(xiàn)
$ echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" | sed '/./,/^$/!d'
Line #1
Line #2
Line #3
這里需要注意的是/./,/^$/!d
這個(gè)命令芹啥,它的意思是匹配區(qū)間/./
到/^$
锻离,區(qū)間的開(kāi)始會(huì)匹配至少包含一個(gè)字符的行,結(jié)束會(huì)匹配一個(gè)空行墓怀,在這個(gè)區(qū)間中的行不會(huì)被刪除汽纠。
模擬grep
命令
$ echo -e "Line #1\nLine #2\nLine #3" | grep 'Line #1'
Line #1
$ echo -e "Line #1\nLine #2\nLine #3" | sed -n '/Line #1/p'
Line #1
模擬grep -v
命令
$ echo -e "Line #1\nLine #2\nLine #3" | grep -v 'Line #1'
Line #2
Line #3
$ echo -e "Line #1\nLine #2\nLine #3" | sed -n '/Line #1/!p'
Line #2
Line #3
模擬tr
命令
tr
命令用于字符轉(zhuǎn)換
$ echo "ABC" | tr "ABC" "abc"
abc
$ echo "ABC" | sed 'y/ABC/abc/'
abc