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

語法

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

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

常用選項

為了幫助理解,筆者將以下文字-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 指令在編寫自動化手稿程式會非常有幫助。完全不再需要自己手動打開設定檔進行編輯。

常用指令

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

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

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 指令,可往上滑看看範例。

常用旗標

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

應用實例

查看檔案內容

查看 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 是取代全部。

參考文獻

除了以上列出的常用選項及指令、旗標。最完整的官方文件可參考以下網址:

最後修改日期: 2020-05-08

作者

留言

撰寫回覆或留言

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