動機:我想了解 sed 指令的原因
最早讓我想了解 sed 指令的原因,是在某次的操作過程中,需要查看目前的 $PATH,到底包含了哪些目錄,所以我下了一道指令:
echo $PATH結果出現了這樣的答案:
面對這麼一長串的文字,我就想如果可以依照字符:來做分割並換行顯示,那我需要的資訊更容易閱讀。於是就 google 了一下:
然後就看到了這個答案:
於是就開始了我對 sed 指令的探索之旅。
sed 指令簡介
sed 全名為 Stream EDitor,是一個使用簡單緊湊的程式語言來解析和轉換文字 Unix 實用程式,是為命令列處理資料檔案而構建的早期 Unix 指令之一。
sed 和 awk 這兩大工具時常被拿來相提並論,因二者一樣強大和對正規表示法有良好的支援。也各自有自己專屬的腳本語言(script language),sed 主要功能為自動化的修改文字檔,而 awk 可想像為超輕量級的 C 直譯語言(Interpreted language)屬通用,偏向統計和需輸出重新排版的應用。
man page 是給已熟悉的人參考用的,用 man page 學 sed 和 awk 就好像用英文字典學英文會話。基本上若直接用 man page 來覺習 sed,這相當有難度,所以若能借用他人的使用心得與範例,相信一定是一個更好的方式。
sed 主要功能:檔案字串修改
grep 雖可利用功能強大的正規表示法搜尋檔案中的字串,但沒辦法對搜尋到的字串進行刪除,取代或插入等編輯動作。補足 grep 編輯功能的工具就是 sed,更甚者 sed 可程式化的特性常用來自動化的修改文字檔。
雖然 vi 也可用來搜尋/修改檔案內容,但要人工把檔案打開,改完再存檔人力要介入很深,如熟悉 sed 的操作這些都可自動化的完成。例如公司搬家,有舊公司地址的表格文件一堆,如善用 sed 就可有效率的自動把所有文件表格上的舊地址改新地址。
sed 用法有點抽象,故對基本用法和每一參數分別說明。
sed 基本用法
sed 和其他功能強大的指令一樣,通常功能愈強語法就愈複雜和抽象,sed 也是如此。如有常自動化的修改文字檔,是值得一學的好工具。
sed 基本的用法如下:
sed [-OPTION] [ADD1][,ADD2] [COMMAND] [/PATTERN][/REPLACEMENT]/[FLAG] [FILE]但光看其晦澀不明的語法是不太可能會使用的,故先舉個例子,一例解千文。
範例一:
我要把檔案 "MyFile.txt" 的 1~8 行中的 "The" 或 "the" 改為大寫的 "THE" 可如下:
sed -e '1,8 s/[Tt]he/THE/g' MyFile.txt其中:
-e:為預設選項,一般的狀況可省略,如沒加任何選項預設是以是 sed -e 選項來執行。
s/[Tt]he/THE/g:sed 最基本的命令,代表搜尋樣板並取代。
s:代表搜尋樣板並取代。
[Tt]he:代表要搜尋樣板文字。
THE:代表將用來取代搜尋到的樣板文字。
g:指令最後的 g 代表搜尋全部範圍。因每一欄參數都可能複雜和抽象,有時 sed 會解讀錯誤,故一般除檔案和選項以外的參數都會用單引號 ' 把其括起來。
範例二:
如欲搜尋和取代的樣板為單字(word),可在樣板和取代字串前加一空隔(因單字間有空隔),例如:有一句子為 "This is a book",我只想把單字 "is" 變大寫,但單字 "This" 也有子串 "is",處理不好輸出會變 "ThIS IS a book"。
echo 'This is a book' | sed 's/is/IS/g'將輸出文字:
ThIS IS a book所以正確的指令應該下為:
echo 'This is a book' | sed 's/ is/ IS/g'
sed 進階用法
Delimiter 分隔符號:
sed 每個參數之間預設分隔符號(delimiter)是用 "/" 來區別如 sed 's/OLD/NEW/g' flie,但如要搜尋樣板有 "/" 會和分隔符號混在一起如再加上跳脫字元 "\" 會變得好像火星文看不懂。
例如:
要把 Linux 路徑 "/abc/wxy" 改為 WINDOWS 路徑表示法的 "\abc\wxy",sed 的寫法為sed 's/\//\\/g'這一串類火星文,真的不易一眼看出什麼是什麼,所以故 sed 允許我們可以用除了空白 ' '、換行 '\n' 以外的字元(英文字母或數字或符號皆可)來當分隔符號,只要前後一致即可。例如:用 : 當作分隔字元:
echo "This ia an apple" | sed 's:ap:Ap:g'例如:Linux 路徑改為 WINDOWS 路徑表示法,用 # 當作分隔字元:
echo "/home/tmps07" | sed 's#/#\\#g'ADDRESS 位址範圍:
sed 位址的表示法可為行號或合法正規表示法的樣板,可為有起始和結束二個位址的範圍或只有單一位址(如第幾行或指定的樣板)。
有些 COMMAND 一定要配合單一位址,大部分的 COMMAND 位址的表示法為範圍,有些 COOMAND 如省略位址表示是全部(如上例搜尋並取代的 COMMAND "s")。
位址範圍的用法各如下:
位址表示法:
為一個起始位址加上一個結束位址,兩者間以 "," 分隔。如只有一個位址則為固定單一位址。$ sed '1,5 s/ [aA]/ one/g' file # 將 1~5 行 "a" 或 "A" 改 "one" $ sed '5 s/ [aA]/ one/g' file # 只將第 5 行 "a" 或 "A" 改 "one" $ sed 's/ [aA]/ one/g' file # 省略位址, 整個檔案 "a" 或 "A" 改 "one"檔案的開頭我們都知道是第一行,但檔案的結尾往往不知是第幾行,此時可用 "$" 來代表最後一行(和 vi 用法一樣,"$" 代表最後一行)。
$ sed '3,$ s/^can/CAN/g' file # 將 3 行到最後一行開頭為 "can" 改大寫樣板表示法:
有起始樣板和結束樣板,每一樣板以成對的 "/" 括起來,起始樣板和結束樣板間以 "," 分隔。例:位址範圍從有 "The" 到 "When" 之間的行,將字串 "can" 改為 "CAN"
$ sed '/The/,/Whe/ s/ can/ CAN/g' < re.txt例:將符合 "[Cc]an$" pattern 的那行 "a" 改 "A"
$ sed '/[Cc]an$/ s/a/A/g' < re.txt混搭表示法:
sed 的位址表示法和樣板表示法是可混合使用的。例:第二行開始到符合 "The" 那行之間任何數字改為字串 "#"
$ sed '2,/The/ s/[0-9]/#/g' < re.txt例:從有 "google" 那行到最後一行的 "a" 改大寫
$ sed '/google/,$ s/a/A/g' < re.txtOPTION 選項:
了解 OPTION 選項時先要了解 sed 指令的一些術語,才不會不知所云。sed 的動作為一次只讀一行並去掉結尾的換行(EOL)到暫時的緩衝區(buffer)中,此暫時緩衝區稱為 "pattern space",接著處理完成後會把 pattern space 的內容送往螢幕後清空 pattern space 再去處理下一行,這樣不斷重複直到檔案結束。
如有內容符合搜尋的樣板之 pattern space 叫 "current pattern space",而 COMMAND "p" 或 "P" 可令 sed 再輸出 current pattern space 到螢幕,其基本的動作流程如下。
sed 主要的選項如下:
語法:
sed [-OPTION] [ADD1][,ADD2] [COMMAND] [/PATTERN][/REPLACEMENT]/[FLAG] [FILE]]註 指令名稱/功能/命令使用者 選項 功能 sed/(stream editor)檔案字串修改/Any -e 執行 sed 的 script 語法 預
設
選
項-f 選用外部的 script 檔來執行 -n 不輸出 pattern space 到螢幕 -l # 和 COMMAND l 一起使用時
l 可以指定每一行的長度#
為
數
字-r 使用延伸正規表示 --help 指令自帶說明 sed 有些選項可獨力運作,但有些選項單獨使用是沒什意義的,如 -n 或 -l 要配合其他 sed COMMAND 才有意義。各選項說明如下:
- -e:執行 sed 的 script 語法
sed 本來就是執行自己專屬的 script 腳本語言,故如都沒選項此為預設選項可省略。但如要搜尋和取代的樣板是多重的,或許多 COMMAND 合併使用,就一定要用 "-e" 選項。
例如:將 "t" 改為 "T" and "pen" 改為 "pencil"$ echo 'this is a pen' | sed -e 's/t/T/' -e 's/pen/&cil/'
例如:許多 sed COMMAND 要使用,就一定要用 "-e" 選項$ echo 'this is a pen' | sed -e 's/t/T/' -e 's/pen/&cil/'- -f:選用外部的 script 檔來執行
如 sed 要處理的任務是多重的,此時可把毎一任務一一寫在一起存成一外部 script 檔,再用選項 "-f" 來指定此外部 script 檔即可。這樣做的好處是規則改變時只要改此外部 script 檔即可,或寫許多 script 檔來處理不同的需求。
例如:有一外部 script 檔 "sed_scr" 功能為把 a~d 改大寫$ cat sed_scr s/a/A/g s/b/B/g s/c/C/g s/d/D/g $ echo 'abcdefg' | sed -f sed_scr ABCDefg- -n:不輸出 pattern space 到螢幕
因 sed 處理完成一行後會把 pattern space 的內容送往螢幕後清空,故如單獨使用選項 "-n" 連 pattern space 也不輸往螢幕故輸出什麼也沒有,故選項 "-n" 一般要配合其他的 sed FLAG 使用才有意義。
一般是配合 sed FLAG "p" 只列出 current pattern space(符合樣板的 pattern),才不會不符合的 pattern 也往螢幕送,此時 sed 的行為可取代 grep。
例如:選項 "-n" 配合 FLAG "p" 只列出符合樣板的行(類似指令 "grep")$ ls -d /etc/* | sed -n '/[A-Z][0-9]/ p'- -l:指定每一行的長度
選項 "-l" (小寫的 L)這選項是配合 COMMAND "l" (小寫的 L)使用,因 sed COMMAND "l" 為把一些 ASCII 控制字元以 "\a"、"\b"、"\t",方式列出,但 ASCII 的控制字元大部分是用來文字定位或排縮,把定位功能取消列印出來可能會影響文字行的長度,故用選項 "-l" 來指定輸出到螢幕的長度。 例如:指定換行的長度=10$ echo -e 'This\tIs\tA\tDog' | sed -nl 10 'l'- -r: 使用延伸正規表示法解讀
預設的情形下,sed 的樣板(pattern)只解讀正規表示法,加選項 "-r" 才會去以延伸正規表示法去解讀樣板。此時如樣板內有如 "?","+" 等符號會被認為是延伸正規表示法的 meta-charaters(表示字元)。不同的解讀結果可是差很多。
例如:正常狀態下,將字串 "99?" 改為 "88"$ echo 'Why an apple $9.99?' | sed 's/99?/88/g' Why an apple $9.88例如:加選項 "-r" 用延伸正規表示法,將字串 "99?" 改為 "88"$ echo 'Why an apple $9.99?' | sed -r 's/99?/88/g' Why an apple $88.88?FLAG 旗幟:
sed FLAG 主要為進一步的控制取代樣板(pattern)的行為,前面我們已用過 FLAG 中的 "g" (global replacement)和 "p" (print)。這兩個 FLAG 是最常使用的,其他的 FLAG 並不常用,了解一下即可,全部的 FLAG 用途如下:
Sed Flags [g][ 數字] 全部取代或指定取代第幾個 I 忽略 pattern 大小寫 p 列印 w 寫入檔案
- g:全部取代
預設 sed 只取代搜尋/取代到第一個樣板此行就停止而去處理下一行,如有g FLAG 則全部搜尋和取代。
例如:"is" → "IS",但預設只取代搜尋/取代到第一個$ echo 'this is an issue' | sed 's/is/IS/' thIS is an issue例如:加 flag "g" 全部取代$ echo 'this is an issue' | sed 's/is/IS/g' thIS IS an ISsue例如:第 3 個符合的樣本才取代$ echo 'aaaaaa aaaaaa' | sed 's/a/A/3' aaAaa aaaaa例如:第 3 個符合的樣本才取代,並重複到結束$ echo 'aaaaaa aaaaaa' | sed 's/a/A/3g' aaAAA AAAAA- I:忽略 pattern 大小寫
此 FLAG 主要對樣板的大小寫一視同仁
例如:$ echo 'this is an apple' | sed 's/APPLE/banana/I' this is an banana- p:列印 current pattern space
如沒此 FLAG,sed 只輸出 pattern space。如加了 "p",FLAG 會再輸出 current pattern space。一般此 FLAG 是和選項 "-n" 合作只輸出符合的 pattern (current pattern space)。
例如:- w:
例如: