溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

怎么學(xué)會(huì)SED

發(fā)布時(shí)間:2022-01-07 10:10:31 來(lái)源:億速云 閱讀:137 作者:柒染 欄目:系統(tǒng)運(yùn)維

怎么學(xué)會(huì)SED,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

下文中用到的測(cè)試文件可以在 https://github.com/mylxsw/sed-demo找到。

概述

SED的英文全稱(chēng)是 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)似于管道的輸入,也可以接受來(lái)自標(biāo)準(zhǔn)輸入流的輸入。

SED由自由軟件基金組織(FSF)開(kāi)發(fā)和維護(hù)并且隨著GNU/Linux進(jìn)行分發(fā),因此,通常它也稱(chēng)作 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專(zhuān)家,你需要知道它的內(nèi)部實(shí)現(xiàn)。SED遵循簡(jiǎn)單的工作流:讀取,執(zhí)行和顯示,下圖描述了該工作流: 

怎么學(xué)會(huì)SED

  • 讀?。?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)有提供輸入文件的話(huà),SED將會(huì)從標(biāo)準(zhǔn)輸入接收請(qǐng)求

  • 如果沒(méi)有提供地址范圍的話(huà),默認(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命令類(lèi)似

$ 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是輸入的文件名稱(chēng),兩個(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ì)話(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)的話(huà),在編輯的文件是符號(hào)鏈接時(shí),SED將會(huì)跟隨鏈接

  • -i[SUFFIX],--in-place[=SUFFIX]:該選項(xiàng)用于對(duì)當(dāng)前文件進(jìn)行編輯,如果提供了SUFFIX的話(huà),將會(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)的話(huà),它將使用NULL字符分割行

循環(huán)

與其它編程語(yǔ)言類(lèi)似,SED提供了用于控制執(zhí)行流的循環(huán)和分支語(yǔ)句。

SED中的循環(huán)有點(diǎn)類(lèi)似于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)簽名的話(huà),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”的行,如果匹配的話(huà)就在這一行的開(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這一行首先檢查上面添加-之后是否滿(mǎn)足四個(gè)-,如果不滿(mǎn)足則跳轉(zhuǎn)到Loop繼續(xù)執(zhí)行第三行,這樣不停的追加-,***如果改行滿(mǎn)足前面有四個(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

我們還可以使用波浪線(xiàn)操作符(~)指定地址范圍,它使用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

必須用正斜線(xiàn)將要指定的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ù)字方式的行尋址類(lèi)似,可以使用加號(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)或者字符串匹配模式,這兩種地址都是可選的。

由命令的名稱(chēng)可以知道,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 命令類(lèi)似,下面是 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à)則會(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ú)的文件。如果人工去做的話(huà),肯定是非常無(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

插入命令與追加命令類(lè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(wèi)命令

$ 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的話(huà),則只有在存在換行符的情況下才進(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)容并且在滿(mǎn)足條件的時(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)了類(lèi)似tac命令類(lèi)似的輸出,將文本內(nèi)容倒序輸出??雌饋?lái)有些晦澀難懂,分解一下卻十分簡(jiǎn)單:

  1. 1!G 這句的意思是出了***行之外,處理每一行的時(shí)候都將保持空間中的內(nèi)容追加到模式空間(正序->倒序)

  2. h 將模式空間中的內(nèi)容復(fù)制到保持空間以備下一行匹配的時(shí)候追加到下一行的后面

  3. $p 如果匹配到***一行的話(huà)則輸出模式空間中的內(nèi)容

  4. 上述步驟不斷重復(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 '\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(xiāo)次,至少匹配N(xiāo)次,匹配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/^M$//' 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命令類(lèi)似的功能。

$ 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 '1s/^$//p;/./,/^$/!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

看完上述內(nèi)容,你們掌握怎么學(xué)會(huì)SED的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

sed
AI