sed 是「stream editor 」的縮寫,顧名思義是進行串流 (stream) 的編輯。無論是在編寫 shell 的或處理 STDIN 的時候,當有需要進行字串取代、複製、刪除的功能,sed 指令是最佳的處理工具。sed 進行取代字串處理時並不會改變目前的檔案,而是將處理過程存放在稱為「模式空間 」(pattern space) 的緩衝區中,結束目前的指令後輸出,接著再處理下一個指令直到檔案結束。

sed 指令主要用於非交互式地處理文本,這意味著你可以在終端機的命令列模式或腳本中使用它來自動處理文件,這讓 sed 指令成為文本處理和數據轉換的有力工具。

sed 指令語法

sed OPTIONS... [SCRIPT] [INPUTFILE...]
  • OPTION - 選項
  • SCRIPT - 動作草稿
  • INPUTFILE - 檔案輸入

動作草稿是包在兩個單引號中執行,支援 Regex 正規表示式替換字串。

sed 指令常用選項

為了幫助理解,筆者將以下文字-PIKO 太郎的成名曲:PPAP 歌詞,存入 sed_example.txt,並以此檔案作為示範。讀者們也可以跟著練習,增強印像。

I have a pen, I have an apple
Ah
Apple pen
I have a pen, I have pineapple
Ah
Pineapple pen
Apple pen
Pineapple pen
Ah
Pen Pie Pineapple Apple Pen
Pen Pie Pineapple Apple Pen

雖然 sed 的選項和指令種類繁多,但實務上經常用到的大致有以下幾種:

  • -n:沉默模式。
  • -e:直接在命令模式編輯。(可不加,請見詳解)
  • -f:程式手稿不直接在命列中打上,而是從指定的檔案中載入。
  • -i:修改檔案。

-n (沉默模式)

在預設情況下,所有資料一般都會被輸出至螢幕上。但如果加上 -n 選項後進入沉默模式,則只有使用 p 指令的那一行才會列出出來。

我們來幾個實例,比較好理解。

範例 (a-1)

sed 's/have/had/1' sed_example.txt

指令 s 是取代,把 have 這個字取代為 had,旗標 /1 指的是在第一次出現的位置。如果是 /2 則是第二次出現的位置,以此類推。

結果:

file

會印出整段檔案中的文字,並把每一行第一次出現 have 的字取代為 had。
注意一下 s 指令只是取代輸出的文字,並不是改變檔案內容。

範例 (a-2) 加入 -n 選項

sed -n 's/have/had/2' sed_example.txt

結果:

無印出結果。因為加入 -n 選項,啟用沉默模式,所以不會輸出任何資料。

範例 (a-3) 加入 -n 選項配合 p 指令

sed -n 's/have/had/2p' sed_example.txt

結果:

file

在旗標中加入 p 指令,則只會列出受影響的行數。

-e (編輯)

範例 (b-1)

 sed -e 's/pen/pencil/' sed_example.txt > sed_output.txt

結果:

file

把檔案中每一行中第一次出現的 pen 換成了 pencil,並存到檔案 sed_output.txt 中。

不加選項 -e 也是可以的。上面的命令列等於:

 sed 's/pen/pencil/' sed_example.txt > sed_output.txt

只有差別在一種情況:當你要在同一行中下多次指令,用 -e 不用分號分隔,不加 -e 則需要加上分號;。我們來看一個例子。

範例 (b-2)

sed 's/pen/pencil/; s/have/had/' sed_example.txt > sed_output2.txt

等於:

sed -e 's/pen/pencil/' -e 's/have/had/' sed_example.txt > sed_output2.txt

輸出

file

這樣的話,應該有清楚這個選項的使用時機了吼 ^^

-f (讀取檔案手稿)

這個選項是讀取存放在檔案中的 sed 程式手稿,比方說我們把以下的文字放進名為 sed_command.txt 的檔案中。

s/pen/pencil/
s/have/had/

範例 (c-1)

sed -f sed_command.txt sed_example.txt > sed_output3.txt

檔案 sed_output3.txt 的內容會是和範例 (b-2) 一樣,這邊就不貼出結果了。由使可知,-f 選項的使用情境是適合在有很多 sed 動作的情況下使用。

-i (修改檔案)

直接修改檔案內容,而不是輸出到螢幕。很常用的選項,常用來進行自動化程式的編寫。

範例 (d-1)

在筆者的 EasyBash 專案中,用來快速安裝 MySQL 的 mysql.sh 裡頭有這麼一行。

sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" ${cnf_path}

在這個實例應用上,當使用者要使用 mysql.sh 安裝 MySQL,下了可遠端登入的指令如下:

./mysql.sh --version=system --secure=y --remote=y --remote-user=test_user --remote-password=12345678

在 Shell 處理的過程中利用 sed 將 my.cnf 中綁定 IP 的設定替換成可由任何 IP 連線的設定。

透過這個實例我們可以了解到,熟悉 sed 指令在編寫自動化手稿程式會非常有幫助。完全不再需要自己手動打開設定檔進行編輯。

sed 常用指令

指令是對字串進行處理的動作,與字串搭配使用的慣例是用單引號'將指令和字串一起包夾起來,如果沒有搭配要字串,可以不使用單引號。使用單引號只是慣例,用雙引號"也是可以的。如果字串是變數的話,則必須使用雙引號,不然會被當成單純的字串。

其實指令很多種,以下只列出最常用的指令。

a (新增)

在指定的行數的「下一行」插入字串。未指定行數的話則是在「每一行」之後插入字串。

語法格式

a text

範例 (e-1)

sed '1a I have both pen and apple' sed_example.txt

在第一行之後插入字串 I have both pen and apple。

輸出

file

範例 (e-2)

sed '1,4a I have both pen and apple' sed_example.txt

這個指令作用是,將第一至第四行之後插入字串。1,4 指的是第一至第四行。

c (替換)

替換指定行數為預替換的字串。

範例 (e-3)

sed '3c I have both pen and apple' sed_example.txt

把第三行整行替換為字串 I have both pen and apple。

輸出

file

範例 (e-4)

sed '1,5c I have both pen and apple' sed_example.txt

把第一至第五行替換為字串 I have both pen and apple。不是每一行會替換為此字串,而是五行變一行,其中四行會消失。

輸出

file

d (刪除)

刪除指定的行。常與 -i 選項搭配,用來修改檔案時移除不需要的行。

範例 (e-5)

sed 1,5d sed_example.txt

刪除第一行至第五行。

範例 (e-6)

sed '/pen/d' sed_example.txt

刪除所有含有 pen 這個字的行。比較特別的是尋找字串刪除的時候的語法格式為:

sed '/text/d'

d 指令在最後面,而不是在前面。

i (插入)

用法和 a 指令一樣,差別在於 a (append) 指令是在指定行數之後插入,而 i (insert) 指令是在指定行數之前插入。

範例 (e-7)

sed '1,3i I have both pen and apple' sed_example.txt

在第一行至第三行的每一行之前都插入字串。

輸出

file

p (列印)

通常配合 -n 選項使用,只列印出受影響的行數。(範例 a-3)

s (取代)

最常用的指令,支援正規表示式(Regular Expression),用來取代字串。

語法格式

s/regexp/replacement/[flags]

本片文章的範例大多使用到 s 指令,可往上滑看看範例。

sed 指令常用旗標

  • [0-9]:數字表示只搜尋或者取代第 N 個數字所指示的那個樣板字串。
  • g:全部取代
  • I:忽略大小寫
  • w:把符合的結果寫入檔案。和加了 -n 選項搭配 p 旗標的結果一樣。此旗標如果有和其它旗標搭配使用,必須放在最後面。

sed 指令應用實例

查看檔案內容

查看 nginx.conf 檔案的第一至第五行。

sed -n '1,5p' /etc/nginx/nginx.conf

結果:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

WordPress 網站換網域名稱

步驟一:先匯出資料庫

mysqldump -uroot -p terrylin_dev > wordpress.sql

這行指令是利用 mysqldump 將資料庫名稱為 terrylin_dev 的資料庫匯出為 wordpress.sql

sed -i 's/terryl.lo/new-domain.com/g' wordpress.sql

wordpress.sql 檔案中所有為 terryl.lo 這個網域名稱字串換成新的網域名稱字串 new-domain.com。旗標 g 是取代全部。

總結

sed 的功能非常強大且有很多選項和命令。這裡只是一個基本介紹。除了以上列出的常用選項及指令、旗標。最完整的官方文件可參考以下網址:

本文列出一些 sed 常被使用的情境,但實務上他被用到的機會非常多,不限於以上的情境。所以要熟列 shell scripting 的技巧的話,sed 是必須熟悉的必備指令唷。

閱讀此文章的英文版:Linux SED.

最後修改日期: 2023-06-24

作者

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。