Linux“文本三劍客”之sed

“文本三劍客”中,grep是文本過濾器,而sed是基于行的文本流編輯器。
sed是將文件中的文本逐行讀取到內(nèi)存中進行處理。

  1. sed工作原理
  2. sed命令
    2.1 OPTION
    2.2 SCRIPT
  3. sed使用示例

1 sed工作原理

sed有兩個工作空間,Pattern space(模式空間)和Hold space(保持空間)。


image.png

Pattern space 模式空間

sed會把文件內(nèi)容的每一行復(fù)制一份出來放到自己的Pattern space中,在其中處理以后,處理的結(jié)果送到stdout(標(biāo)準(zhǔn)輸出):

  1. 默認(rèn)情況sed會處理每一行,但我們可以讓sed處理只被模式(如正則表達(dá)式)匹配到的文本。
  2. Pattern space中被用戶給出的模式匹配到的內(nèi)容,則edit(編輯)后再送到stdout。
  3. 如果不能匹配,則不做任何編輯操作,直接輸出到stdout。

Hold space 保持空間

Hold space用于在使用高級編輯功能時,實現(xiàn)與Pattern space空間中的內(nèi)容進行追加、覆蓋、互換等操作。后邊高級編輯示例中會詳細(xì)解釋。

2 sed命令

sed - stream editor for filtering and transforming text
sed [OPTION]... 'SCRIPT' [input-file]...
sed命令需要將命令選項OPTION和處理腳本SCRIPT結(jié)合使用,來對文本進行特定的處理動作。

2.1 OPTION

  • -n:不輸出模式空間的內(nèi)容至屏幕stdout
    [默認(rèn)情況下,會將不被pattern匹配到的內(nèi)容直接輸出到stdout,-n則不輸出這部分內(nèi)容]
  • -e script,--expression=script:多點編輯;
    默認(rèn)只支持一個script(被pattern匹配到的內(nèi)容將被執(zhí)行的編輯命令),加-e可以指定多個script。
    如:sed -e 's@^#[[:space:]]*@@' -e '/^UUID/d' /etc/fstab
  • -f /PATH/TO/SED_SCRIPT_FILE
    SED_SCRIPT_FILE中,每行都有一個script,從文件中逐行讀取script,省去-e的繁瑣
  • -r,--regexp-extended:支持?jǐn)U展正則表達(dá)式
  • -i[SUFFIX],--in-place[=SUFFIX]:直接編輯原文件(有風(fēng)險,用之前先做備份)(sed默認(rèn)不直接編輯原文件)。

2.2 SCRIPT

SCRIPT由"地址定界"和"編輯命令"兩部分組成,和vi編輯器的末行模式命令相似。兩部分中間無空格。

地址定界的語法格式
  1. 地址定界為空,表示全文;
  2. 單地址:
    N:指定一個行號,表示第N行;
    /PATTERN/:給出一個模式,表示被模式匹配到的每一行。
  3. 地址范圍:
    M,N:表示從第M行到第N行;
    M,+N:表示從第M行開始,到往后N行之間的所有行(包含第M行);
    M,/PATTERN/:表示從第M行到被PATTERN匹配到的第一行之間的所有行
    /PATTERN1/,/PATTERN2/:表示從被PATTERN1匹配到的第一行,到被PATTERN2匹配到的第一行之間的所有行。
  4. 用“~”表示步進:
    如:1~2表示所有奇數(shù)行,2~2表示所有偶數(shù)行。
編輯命令
  1. d:delete pattern space,刪除模式匹配到的內(nèi)容(模式空間中的內(nèi)容)
    d是一個特殊的操作
  2. p:print the current pattern space:打印模式匹配到的內(nèi)容(模式空間中的內(nèi)容)
    p也是一個特殊的操作,會將pattern匹配到的內(nèi)容顯示兩遍,如果不加選項,顯示結(jié)果為,模式空間中的全部內(nèi)容+被pattern匹配到的內(nèi)容;
    如果只想顯示被pattern匹配的內(nèi)容,配合使用-n選項,將不顯示默認(rèn)輸出的模式空間全部內(nèi)容。
  3. a \text:append,在模式匹配到的行后面追加文本“text”,支持使用\n(換行符號)實現(xiàn)多行追加(注意文本前用\轉(zhuǎn)義)
  4. i:insert,在模式匹配到的行前面插入文本“text”,支持使用\n(換行符號)實現(xiàn)多行插入(注意文本前用\轉(zhuǎn)義)
    比如,在fstab文件中所有以UUID開頭的行前面加入注釋:
    sed '/^UUID/i # Add device based on UUID.' fstab
  5. c \text:把匹配到的行替換為"text"(注意是整行替換?。。?;
  6. w /PATH/TO/SOMEFILE:保存模式匹配到的行至指定的文件中;
    例如:將fstab中所有以非#開頭的行保存到當(dāng)前目錄下的fstab.new文件中:
    sed '/[#]/w fstab.new' fstab
  7. r /PATH/FROM/SOMEFILE:讀取指定文件的內(nèi)容至當(dāng)前文件被模式匹配到的行后面;
    例如:將/etc/issue文件中的內(nèi)容顯示到fstab文件第3行的后面:
    sed '3r /etc/issue' fstab
  8. =:為模式匹配到的行打印行號(在行的前面另起一個新行來打印行號);
    例如:將fstab中所有以UUID開頭的行都打印行號:
    sed '/^UUID/=' fstab
  9. !:條件取反(!放在地址定界和編輯命令之間)
    地址定界!編輯命令
    例如:前邊有個例子,“將fstab中所有以非#開頭的行保存到當(dāng)前目錄下的fstab.new文件中”
    我們使用 “sed '/[#]/w fstab.new' fstab”;
    在這里可以這樣“ sed '/^#/!w fstab.new' fstab”,它表示所有#號開頭的行都不寫入fstab.new文件,即非#開頭的行就寫入。
  10. s///:查找替換,其分隔符可自行指定,常用的有s@@@,s###等;
    替換標(biāo)記:
    g:全局替換
    w /PATH/TO/SOMEFILE:將替換成功的結(jié)果保存至指定文件中;
    p:顯示替換成功的行;
高級編輯命令

高級編輯命令用于Pattern space和Hold space中內(nèi)容的追加、覆蓋和互換,有以下幾個:

  1. Pttern space --> Hold space
    h:把模式空間中的內(nèi)容覆蓋至 > 保持空間(hold space)中;
    H:把模式空間中的內(nèi)容追加至 >> 保持空間(hold space)中;
  2. Hold space --> Pattern space
    g:把保持空間中的內(nèi)容覆蓋至 > 模式空間中;
    G:把保持空間中的內(nèi)容追加至 >> 模式空間中;
  3. 模式匹配的下一行 --> Pattern space
    n:覆蓋讀取匹配到的行的下一行至 > 模式空間中
    N:追加讀取匹配到的行的下一行至 >> 模式空間中
  4. Pattern space <--> Hold space
    x:把模式空間中的內(nèi)容與保持空間中的內(nèi)容互換;
  5. 刪除Pattern sapce中的行
    d:刪除模式空間中的行
    D:刪除多行模式空間中的所有行(多行模式空間比如,N命令追加到模式空間中行)

3 sed使用示例

普通編輯命令示例

sed是否用得好,主要是看SCRIPT的編寫能力。

  1. 刪除/etc/grub2.cfg文件中所有以空白字符開頭的行的行首的所有空白字符:
    sed 's@^[[:space:]]\+@@' /etc/grub2.cfg
  2. 刪除/etc/fstab文件中所有以#開頭的行的行首的#號及#后邊的所有空白字符:
    sed 's@^#[[:space:]]*@@' /etc/fstab
  3. 輸出一個絕對路徑給sed命令,要求取出其目錄名,類似dirname命令執(zhí)行結(jié)果:
    echo "/var/log/messages" | sed 's@[^/]\+/\?$@@'
    或使用-r選項支持?jǐn)U展正則表達(dá)式:
    echo "/var/log/messages" | sed -r 's@[^/]+/?$@@'

高級編輯命令示例與命令解析

要使用sed的高級編輯命令,需要對sed的工作流程非常熟悉。

  • sed -n 'n;p' FILE
    顯示偶數(shù)行(;分號用來分隔多個命令)
    命令解析:
    因為是n;p,沒有地址定界,表示逐行讀取所有內(nèi)容。
    1、首先讀取第1行到pattern space,遇到第一個命令是n,覆蓋讀取下一行(也就是第2行)到pattern space,所以現(xiàn)在pattern space中的內(nèi)容變?yōu)榈?行(第1行被覆蓋掉);
    2、然后是p命令,將pattern space中的第2行顯示出來;
    3、接著讀取第3行到pattern space,同上,顯示第4行;
    4、以此類推,顯示所有偶數(shù)行。

注意:如果沒有-n選項,則將顯示全部內(nèi)容,并且偶數(shù)行顯示兩遍。

  • sed '1!G;h;$!d' FILE
    逆序顯示文件內(nèi)容,相當(dāng)于tac
    命令解析:
    1、讀取第1行到pattern space,先碰到“1!G”命令,表示第1行不做G操作;
    2、然后碰到下一個命令“h”,表示將pattern space中的內(nèi)容覆蓋至hold space,就是將第1行內(nèi)容復(fù)制到了hold space中;
    3、接下來碰到“$!d”命令,表示將pattern space中不是最后一行的內(nèi)容全部刪除,pattern space中當(dāng)前還有第1行的內(nèi)容,則將其刪除。第1行的讀取到此結(jié)束。
    4、接著讀取第2行,“1!G”命令將hold space中的內(nèi)容(第1行的內(nèi)容)覆蓋至pattern space,所以目前pattern space中的內(nèi)容變?yōu)椤暗?行+第1行”;
    5、然后碰到“h”命令,將pattern space中的內(nèi)容(第2行+第1行)復(fù)制到hold space中(hold space中原來的第1行內(nèi)容被覆蓋掉),所以現(xiàn)在hold space中的內(nèi)容為“第2行+第1行”;
    6、下一個命令“$!d”,同上,將pattern space中的“第2行+第1行”內(nèi)容刪除。
    第2行的讀取到此結(jié)束。
    7、以此類推,知道讀取第n-1行結(jié)束時,hold space的內(nèi)容為“第n-1行+第n-2行....第2行+第1行”,pattern space為空;
    8、最后讀取第n行,“1!G”命令將hold space內(nèi)容追加到pattern space,則pattern space內(nèi)容變?yōu)椤暗趎行...第1行”;
    9、“h”命令將pattern space的內(nèi)容覆蓋復(fù)制到hold space,則現(xiàn)在hold space的內(nèi)容為“第n行...第1行”;
    10、最后碰到“$!d”命令,因為是最后一行,則不刪除pattern space的內(nèi)容,所以pattern space中的內(nèi)容還是“第n行...第1行”。
    11、讀取完全部內(nèi)容后,默認(rèn)輸出pattern space中的全部內(nèi)容,即“第n行...第1行”,將原內(nèi)容逆序顯示!

  • sed '$!d' FILE
    取出最后一行,相當(dāng)于tail -1
    命令解析:
    1、讀取第1行到pattern space,pattern中的命令為“$!d”(不是最后一行,則刪除),所以把第1行從pattern space中刪了
    2、依次類推,一直刪到倒數(shù)第2行;
    3、到最后一行,不刪了,保留在pattern space中,然后輸出到stdout。

  • 其他幾個高級編輯命令示例
    sed '$!N;$!D' FILE:顯示最后兩行,相當(dāng)于tail -2
    sed '/^$/d;G' FILE:刪除原有所有空白行,再為所有非空白行后添加一個空白行
    sed 'n;d' FILE:顯示奇數(shù)行;
    sed 'G' FILE:在原有的每行后方添加一個空白行;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容