Shell 基礎 -- 流編輯器 sed 詳解

1、流編輯器 sed 與命令 sedshell

  Linux 中,常使用流編輯器 sed 進行文本替換工做。與常使用的交互式編輯器(如vim)不一樣,sed 編輯器以批處理的方式來編輯文件,這比交互式編輯器快得多,能夠快速完成對數據的編輯修改。編程

  通常來講,sed 編輯器會執行如下操做:vim

1)一次從輸入中讀取一行數據;bash

2)根據所提供的編輯器命令匹配數據;編輯器

3)按照命令修改流中的數據;學習

4)將新的數據輸出到 STDOUT。spa

  在 sed 編輯器匹配完一行數據後,它會讀取下一行數據並重復這個過程,直處處理完全部數據。使用 sed 命令打開一個 sed 編輯器。sed 命令的格式以下:命令行

sed [options] edit_commands [file]    # [ ] 中的內容爲可選可不選

   其中,options 爲命令選項,選擇不一樣的 options 能夠修改 sed 命令的行爲,主要有 3 個選項:code

1)-e 選項: 在處理輸入時,將 script 中指定的編輯命令添加到已有的命令中。通俗的說,就是在 sed 後面直接添加編輯命令:blog

sed -e 'edit_commands' [files]

  sed 命令在默認狀況下使用的是 -e 選項。當只有一個編輯命令時,-e 選項能夠省略;可是當要在一條 sed 語句中執行多個編輯命令時,就須要使用 -e 選項了:

sed -e 's/root/ROOT/g; s/bin/BIN/g' /etc/passwd       # 使用 sed 同時執行兩條編輯命令(本文大部分用例都直接使用 /etc/passwd 文件)

sed -e 's/root/ROOT/g' -e 's/bin/BIN/g' /etc/passwd   # 使用 sed 同時執行兩條編輯命令

2)-f 選項:在處理輸入時,將 file 中指定的編輯命令添加到已有的命令中:

  前面提到,在須要同時執行多條編輯命令時,可使用 -e 選項。可是當所須要執行的編輯命令數量不少時,每次使用 sed 時一行一行地敲顯然不是很方便,這時能夠將所用到的 sed 編輯命令寫入一個文件,而後使用 sed -f 選項來指定讀取該文件:

$ cat script.sed
$ s/root/ROOT/
$ s/bin/BIN/
$ s/home/HOME/
sed -f script.sed /etc/passwd

3)-n 選項: 不產生命令輸入:

sed -n 's/root/ROOT/' /etc/passwd

  使用 -n 選項不會將流編輯器的內容輸出到 STDOUT,一般將 -n 選項與 p 命令結合起來使用,以只打印被匹配的行。

  除了這三個選項外,sed 編輯器還提供了許多命令,用來進行更詳細的操做,簡單列一下,後面再仔細介紹:

命令 描述
s 文本替換操做
d 刪除操做
i 插入操做
a 附加操做
c 將一行文本修改成新的行
y 逐字符替換
p 打印文本行
= 打印行號
w 向文件中寫入數據
r 從文件中讀取數據

 

2、使用 sed 命令進行文本替換

   sed 使用 s 命令來進行文本替換操做,基本格式以下:

sed 's/srcStr/dstStr/' file

  其中,srcStr 爲想要替換的文本,dstStr 爲將要替換成的文本。使用 s 命令時,sed 編輯器會在一行一行地讀取文件 file,並在每行查找文本 srcStr,若是找到了,則將該處的 srcStr 替換爲 dstStr。

  / 字符爲界定符,用於分隔字符串(sed 編輯器容許使用其餘字符做爲替換命令中的字符串分隔符):

sed 's!/bin/bash!/BIN/BASH!' /etc/passwd    # 使用 ! 做爲字符串分隔符

  默認狀況下,替換命令只會替換掉目標文本在每行中第一次出現的地方。若想要替換掉每行中全部匹配的地方,可使用替換標記 g。替換標記放在編輯命令的末尾。除了 g 外,還有幾種替換標記:

1)數字:指明替換掉第幾回匹配到的文本,沒有設置這個標記時,默認是替換第一次匹配的文本:

sed 's/root/ROOT/2' /etc/passwd

  這行命令將 /etc/passwd 文件中每行的第 2 個 root 替換爲 ROOT;

2)g :替換全部匹配到的文本:

sed 's/root/ROOT/g' /etc/passwd

   這行命令將 /etc/passwd 文件中的 root,所有替換爲 ROOT;

3)p :打印與替換命令中指定模式(srcStr)相匹配的行:

sed 's/root/ROOT/p' /etc/passwd

  執行這命令,會在 STDOUT 上看到包含有 root 的行被輸出了兩次,一次是 sed 編輯器自動輸出的;另外一次則是 p 標記打印出來的匹配行。

  單獨地使用 p 標記沒什麼用處,一般將 p 標記和 -n 選項結合起來使用,這樣就能夠只輸出被匹配替換過的行了:

sed -n 's/root/ROOT/gp' /etc/passwd    # 將 /etc/passwd 中全部的 root 都替換成 ROOT,並輸出被修改的行

  注:可使用 " = " 命令來打印行號,用法與 p 同樣。  

4)w file :將替換的結果寫到文件中,不過只保存被修改的行,與 -n + p 的功能相似:

sed -n 's/root/ROOT/g w change.txt' /etc/passwd     # 將 /etc/passwd 中全部的 root 都替換成 ROOT,並將被修改的行保存到文件 change.txt 中去

 

3、使用行尋址對特定行進行編輯

  默認狀況下,sed 編輯器會對文件中的全部行進行編輯。固然,也能夠只指定特定的某些行號,或者行範圍來進行流編輯,這須要用到行尋址。所指定的行地址放在編輯命令以前:

[address] commands

3.1 使用數字方式進行行尋址

  sed 編輯器將文本流中的每一行都進行編號,第一行的編號爲 1 ,後面的按順序分配行號。經過指定特定的行號,能夠選擇編輯特定的行。舉幾個例子:

sed '3 s/bin/BIN/g' /etc/passwd    # 將第3行中全部的 bin 替換成 BIN
sed '2,5 s/bin/BIN/g' /etc/passwd   # 將第2到5行中全部的 bin 替換成 BIN sed '10,$ s/bin/BIN/g' /etc/passwd  # 將第10行到最後一行中全部的 bin 替換成 BIN

   注:行尋址不止對替換命令有效,對其餘命令也都是有效的,後面也會用到。

 

3.2 使用文本模式過濾器過濾行

  sed 編輯器容許指定文本模式來過濾出命令要做用的行,格式以下:

/pattern/command

  必須使用斜槓符 " / " 將要指定的文本模式 pattern 包含起來。sed 編輯器會尋找匹配文本模式的行,而後對這些行執行編輯命令:

sed -n '/root/s/bin/BIN/p' /etc/passwd    # 尋找包含有字符串 root 的行,並將匹配行的 bin 替換爲 BIN

  與數字尋址同樣,也可使用文本過濾區間來過濾行:

sed '/pattern1/,/pattern2/ edit_command' file

  這行命令會在文件 file 中先尋找匹配 pattern1 的行,而後從該行開始,執行編輯命令,直到找到匹配 pattern2  的行。可是須要注意的是,使用文本區間過濾文本時,只要匹配到了開始模式(pattern1),編輯命令就會開始執行,直到匹配到結束模式(pattern2),這會致使一種狀況:一個文本中,先匹配到了一對 pattern一、pattern2,對該文本區間中的文本執行了編輯命令;而後,在 pattern2 以後又匹配到了 pattern1,這時就會再次開始執行編輯命令,所以,在使用文本區間過濾時要格外當心。舉個例子:

sed -n '/root/,/nologin/ s/bin/BIN/p' /etc/passwd

  這行命令對 /etc/passwd 進行了兩次文本區間匹配,結果以下:

  

4、使用 sed 命令刪除行

   sed 編輯器使用 d 命令來刪除文本流中的特定行。使用 d 命令時,通常須要帶上位尋址,以刪除指定的行,不然默認會刪除全部文本行:

sed '/root/d' /etc/passwd   # 刪除匹配 root 的行

sed '2,$d' /etc/passwd    # 刪除第2到最後一行

 

5、使用 sed 命令插入和附加文本

  sed 編輯器使用 i 命令來向數據流中插入文本行,使用 a 命令來向數據流中附加文本行。其中:i 命令會在指定行前增長一個新行;a 命令會在指定行後增長一個新行。

  須要注意的是,這兩個命令都不能在單個命令行上使用(即不是用來在一行中插入或附加一段文本的),只能指定插入仍是附加到另外一行。命令格式以下:

sed '[address][i | a]\newline' file

  newline 中的文本即爲將要插入或附加在一行前面或後面的文本。經常使用這兩個命令結合行尋址在特定的行前面或後面增長一個新行。舉個例子:

sed 'i\Insert a line behind every line' /etc/passwd      # 向數據流的每一行前面增長一個新行,新行的內容爲 \ 後面的內容

sed '1i\Insert a line behind the first line' /etc/passwd   # 在數據流的第一行前面增長一個新行

sed '3a\Append a line after the third line' /etc/passwd      # 在數據流的第三行後面增長一個新行
    
sed '$a\Append a line in the last line' /etc/passwd      # 在數據流的最後一行後面增長一個新行

 

6、使用 sed 命令修改行

  使用命令 c 能夠將數據流中的整行文本修改成新的行,與插入、附加操做同樣,這要求在 sed 命令中指定新的行,格式以下:

sed '[address][c]\newtext' file

  newtext 中的文本爲匹配行將要被修改爲的文本。

sed '3 c\New text' /etc/passwd     # 將數據流中第三行的內容修改成 \ 後面的內容

sed '/root/ c\New text' /etc/passwd  # 將匹配到 root 的行的內容修改成 \ 後面的內容

sed '2,4c\New text' /etc/passwd     # 將第2到4行的內容修改成 \ 後面的內容,可是不是逐行修改,而是會將這之間的 3 行用一行文原本替代

  注意這裏對地址區間使用 c 命令進行修改時,不會逐行修改,而是會將整個區間用一行修改文本替代。 

 

7、使用 sed 命令逐字符轉換

  使用 y 參數能夠按要求對文本進行逐字符轉換。格式以下:

[address]y/inchars/outchars/

  轉換命令會對 inchars 和 outchars 的值進行一對一的映射。inchars 中的第一個字符會被轉換成 outchars 中的第一個字符;inchars 中的第二個字符會被轉換成 outchars 中的第二個字符;... 直處處理完一行。若是 inchars 和 outchars 的長度不一樣,則 sed 編輯器會產生一個錯誤消息。舉個例子:

echo abcdefggfedcba | sed 'y/acg/ACG/'

   輸出結果爲 AbCdefGGfedCbA。

 

8、使用 sed 命令處理文件

8.1 向文件中寫入數據

  前面已經提到過,可使用 w 命令向文件寫入行。格式以下:

[address]w filename

  舉個例子:

sed '1,2w test.txt' /etc/passwd

   該語句將數據流的第 一、2 行寫入文件 test.txt 中去。

 

8.2 從文件中讀取數據

  可使用 r 命令來將一個文本中的數據插入到數據流中去,與普通的插入命令 i 相似,這也是對行進行操做的,命令格式以下:

[address]r filename

  filename 爲要插入的文件。r 命令常結合行尋址使用,以將文本插入到指定的行後面。舉個例子:

sed '3 r test.txt' /etc/passwd

   這句話將文件 test.txt 中的內容插入到數據流第三行後面去。

 

參考書籍:

《Linux命令行與shell腳本編程大全》 (第3版)

《Shell腳本學習指南》

相關文章
相關標籤/搜索