linux sed 命令

sparkdev發表於2017-07-10

sed 是一個流編輯器(stream editor),主要用來執行文字替換。但 sed 的主要設計目的是以批處理的方式而不是互動的方式來編輯檔案。

命令簡介

基本命令格式

sed [常用選項] 命令文字 輸入

常用選項

    -n (--quiet, --silent):安靜模式。在 sed 的基本用法中,所有來自標準輸出的資訊都會被列出到終端上。加上 -n 引數後,則只有被sed 處理的那些行才會被輸出。
    -e:指定在指令列模式上執行的命令文字。預設不需要指定,只有同時要執行多個命令文字時才需要顯式的指定 -e 選項。
    -f:同時要執行多個命令文字時,可以將這些命令文字寫到一個檔案中,然後通過 -f filename 的方式使用。
    -r:sed 預設使用基礎正規表示式語法(BRE),指定 -r 選項後使用擴充套件正規表示式語法(ERE)。
    -i:直接修改讀取的文件,而不是輸出到終端。

常用命令

    a:新增行, a 的後面接字串,這些字串會被新增到匹配行的下面。
    c:替換行, c 的後面接字串,這些字串會替換掉匹配到的行。
    d:刪除行,刪除匹配到的行。
    i:插入行, i 的後面接字串,這些字串會被插入到匹配行的上面。
    p:列印,將某些行輸出。通常 p 會與引數  -n 一起使用,這樣只輸出匹配到的行。
    s:字串替換,主要搭配正規表示式使用。

解釋一下本文中 "命令" 與 "命令文字" 的區別:
命令是一些抽象的操作,比如 a 指示新增行,d 指示刪除行。
命令文字則是由命令和其它一些資訊組合起來的一個字串,用來執行具體的操作。
比如在第一行下面新增一行,內容為 'Hello world',命令文字為:'1a Hello world'
再如刪除包含字串 'Hello world' 的行,命令文字為:'/Hello world/d'

常用選項及命令詳解

說明:本文示例中 demo 檔案 test.txt 包含三行文字,內容為:

aa
bb
cc

demo 檔案 hello.txt 包含三行文字,內容為:

Hello world! Hello Jack!
Hello China!
Hello Nick!

刪除行

刪除行需要使用命令 d:

$ sed '1d' test.txt            # 刪除第一行
$ sed '$d' test.txt            # 刪除最後一行
$ sed '1,2d' test.txt          # 刪除第一行到第二行
$ sed '2,$d' test.txt          # 刪除第二行到最後一行

注意,執行完上面的命令,我們只能在命令列終端上看到正確的結果,而 test.txt 檔案根本沒有發生變化:

選項 -i

如果想要直接在原檔案上進行修改(其實是先修改檔案的內容,然後儲存到原檔案中),需要使用選項 -i:

$ sed -i '1d' test.txt

注意,應用 -i 選項後命令列上沒有輸出內容,但是原始檔被更新了。

新增行

a 命令可以在匹配的行下面新增行:

$ sed '1a Hello world!' test.txt                  # 在第一行下面新增一行,內容為 "Hello world!"
$ sed '$a Hello world!' test.txt                  # 在最後一行下面新增一行,內容為 "Hello world!"
$ sed '1,3a Hello world!' test.txt                # 在第一行,第二行和第三行下面分別增加一行,內容  
                                                  # 為 "Hello world!" 1,3 表示從第一行到第三行
$ sed '1a Hello world!\nHello China!' test.txt    # 一次增加多行需要使用換行符 \n

選項 -e

-e 選項用來指定命令文字,如果只有一個命令文字時 -e 選項可以省略。如何要指定多個命令文字就需要使用 -e 選項。

$ sed -e '1a xxx' -e '2a yyy' test.txt

插入行

i 命令可以在匹配的行上面插入行,語法與新增行相同,只是新行在指定行的上面(與 a 命令的區別):

選項 -f

前面我們通過選項 -e 新增了多個命令文字,但是如果需要新增比較多的命令文字,使用選項 -e 就不太合適了。因為把所有的命令文字全部寫在命令列中會導致維護困難。此時選項 -f 就派上用場了。我們可以把多個命令文字寫入到文字檔案中,然後通過 -f 選項進行引用。
我們建立一個叫 commands 的檔案,在裡面新增三個命令文字如下:

1i Hello world!
2i Hello world!
3i Hello world!

然後執行命令:

$ sed -f commands test.txt

通過 -f 選項,commands 檔案中的三個命令文字都被執行了!

替換行

使用 c 命令可以輕鬆的進行整行替換:

$ sed '1c  Hello world!' test.txt         # 把第一行替換為 "Hello world!"
$ sed '1,3c Hello world!' test.txt        # 把第一行到第三行替換為 "Hello world!"

注意,上圖中的命令把三行文字替換成了一行文字!

字串替換

與行替換不同,s 命令只替換匹配到的內容(一般為字串):

$ sed 's/Hello/Hi/' hello.txt             # 把Hello 替換為 Hi

上圖帶給我們的困惑之一是:為什麼第一行中只有第一個 Hello 被替換了?答案是 sed 預設只會替換第一個匹配到的內容!那麼我們的第二個困惑來了:如果只替換第一個匹配到的內容,那麼為什麼第二行和第三行的 Hello 都被替換了呢?這個問題涉及的 sed 的工作方式,sed 是一個以行為單位進行文字處理的工具!所以圖中的三行是被分為三次,每次一行進行處理的。因而第二行和第三行中的 Hello 對於本行來說都是第一個匹配到的內容,被替換是正確的。
要進行全域性替換,需要在命令文字中指定 g,試試下面的命令:

$ sed 's/Hello/Hi/g' hello.txt             # 把匹配到的所有Hello 都替換為 Hi

這下第一行中的兩個 Hello 都被替換了。

我們還可以限制執行替換操作的行:

$ sed '2,3s/Hello/Hi/g' hello.txt          # 只在第二行和第三行進行替換操作

當然也可以通過替換來刪除不需要的字串:

$ sed 's/Hello//g' hello.txt               # 刪除字串 Hello

定界符

雖然 / 是最常用的定界符,但是你也可以使用其它的字元。舉個簡單的例子,當你要在 linux 下進行路徑替換時,使用 / 作為定界符是很不爽的(需要很多的轉義符),此時換一個定界符是最好的解決方案:

上圖中我們使用分號作為定界符輕鬆實現了路徑替換。

匹配

細心的同學可能已經注意到了,sed 所有的操作都是建立在行定位之上的。也就是說無論你要幹什麼,都要先找到(匹配)目標行。連最簡單的刪除行 '1d',也得先定位到第一行,然後才能刪除。所以唯一能限制我們發揮 sed 能力的因素就是:如何匹配到期望的行?

答案是掌握基本的規則,然後多練習! -n 選項和 p 命令是我們練習的好幫手。-n 選項告訴 sed 只輸出那些被處理過的行。比如 sed '1a Hello world!' test.txt 命令預設會輸出四行,應用 -n 後只輸出一行:

p 命令則告訴 sed 只輸出那些匹配到的行, 比如命令:

$ sed -n '1p' test.txt 和命令sed -n '2,3s/Hello/Hi/gp' hello.txt

行匹配的規則大概有兩類:通過行號進行匹配和通過正規表示式進行匹配。

下面是一些通過行號進行匹配的例子:

$ sed -n '1p' test.txt                 # 匹配第一行
$ sed -n '$p' test.txt                 # 匹配最後一行
$ sed -n '2,3p' test.txt               # 匹配第二行和第三行
$ sed -n '3,$p' test.txt               # 匹配第三行和第三行後的每一行

下面是通過正規表示式進行匹配的例子:

$ sed -n '/Hello/p' hello.txt

預設的匹配是區分大小寫的,要忽略大小寫可以使用I(大寫字母i)

$ sed -n '/hello/Ip' hello.txt

下面幾個是正規表示式匹配後執行操作的例子:

$ sed '/Hello/d' hello.txt                # 找到匹配的行,並刪除
$ sed '/Hello/a world!' hello.txt         # 找到匹配的行,並在它們下面新增新行
$ sed 's/world/China/g' hello.txt # 把行中的 world 替換為 China $
sed '/Hello/s/world/China/g' hello.txt # 找到匹配的行,在這些行中執行替換

下面的例子通過正規表示式進行整行內容的替換:

$ sed -i 's/^commonName.*/commonName = xxx/g' my.cnf
$ sed -i 's/^subjectAltName.*/subjectAltName = DNS:xxx/g' my.cnf

總結

sed 是一個強有力的文字替換工具,尤其是需要在自動化的場景中使用的時候。本文結合例項比較詳細的介紹了 sed 的使用方法,希望對大家瞭解、使用 sed 有所幫助。

相關文章