12、sed文本處理

 

 

1、概述

1.sed 是一款流編輯工具,用來對文本進行過濾與替換工做,特別是當你想要對幾十個配置文件作統計修改時,你會感覺到 sed 的魅力!
sed 經過輸入讀取文件內容,但一次僅讀取一行內容進行某些指令處理後輸出,因此 sed更適合於處理大數據文件。
2.sed 流程:
* 經過文件或管道讀取文件內容。
* sed 並不直接修改源文件,而是將讀入的內容複製到緩衝區中,咱們稱之爲模式空間(pattern space)。
* 根據 sed 的指令對模式空間中的內容進行處理並輸出結果,默認輸出至標準輸出即屏幕上。html

 

 

2、sed 語法和基本命令



 

基本用法

 

sed [options] {sed-commands} {input-file}

 

 sed 每次從 input-file 中讀取一行記錄,並在該記錄上執行 sed-commands
sed 首先從 input-file 中讀取第一行,而後執行全部的 sed-commands;再讀取第二行,執行全部 sed-commands,重複這個過程,直到 input-file 結束
經過制定[options] 還能夠給 sed 傳遞一些可選的選項
node

 

 

 

常見命令選項;改變數據處理的方式

 

 

命令選項    註釋
-n    屏蔽默認輸出(所有文本),再也不默認顯示模式空間中的內容
-i,--in-place      直接修改源文件內容
-f    -f script-file,--file=script-file              從文件中讀取腳本指令,對編寫自動腳本程序來講很棒!
-e SCRIPT -e SCRIPT:能夠同時執行多個腳本
-r    啓用擴展的正則表達式,若與其餘選項一塊兒使用,應做爲首個選項
{}    可組合多個命令,以分號分隔
--version                     顯示 sed 版本。
--help                           顯示幫助文檔。
-l N, --line-length=N       該選項指定 l 指令能夠輸出的行長度,l 指令用於輸出非打印字符。
--posix                     禁用 GNU sed 擴展功能。

 

下面的例子演示了 sed 的基本語法,它打印出/etc/passwd 文件中的全部行
web

sed –n 'p' /etc/passwd


該例子的重點在於, {sed-commands}既能夠是單個命令,也能夠是多個命令。你也能夠把多個 sed 命令合併到一個文件中,這個文件被稱爲 sed 腳本,而後使用-f 選項調用它,以下面的例子:
使用 sed 腳本的基本語法:
正則表達式

sed [ options ] –f {sed-commands-in-a-file} {input-file}

 


下面的例子演示了使用 sed 腳本的用法,這個例子將打印/etc/passwd 問中以 root nobody
開頭的行:
shell

vi test-script.sed
/^root/ p
/^nobody/ p
$ sed –n –f test-script.sed /etc/passwd

 


你也可使用 –e 選項,執行多個 sed 命令,以下所示:
-e 的使用方法
express

sed [ options ] –e {sed-command-1} –e {sed-command-2} {input-file}

 

下面的例子演示了-e 的使用方法,它打印/etc/passwd 中以 root nobody 開頭的行:vim

[root@ceph-node5 ~]# sed -n -e '/^root/ p' -e '/^nobody/ p' /etc/passwd 

 


若是使用-e 執行多個命令,也可使用反斜槓\把它們分割到多行執行:
緩存

sed -n \
-e '/^root/ p' \
-e '/^nobody/ p' \
/etc/passwd

 


也可使用{ }將多個命令分組執行:
{}的使用方法:
bash

sed [options] '{
sed-command-1
sed-command-2
}' input-file

 


下面的例子演示了{}的使用方法,打印/etc/passwd 中以 root nobody 開頭的行:
app

sed -n '{
/^root/ p
/^nobody/ p
}' /etc/passwd

 


注意:sed 毫不會修改原始文件 input-file,它只是將結果內容輸出到標準輸出設備。 若是要保持變動,應該使用重定向 > filename.txt

 

 

Sed 腳本執行流程

Sed 腳本執行聽從下面簡單易記的順序: Read,Execute,Print,Repeat(讀取,執行,打印,重複)
簡稱 REPR
分析腳本執行順序:

讀取一行到模式空間(sed 內部的一個臨時緩存,用於存放讀取到的內容)
在模式空間中執行命令。若是使用了{ } 或 –e 指定了多個命令, sed 將依次執行每一個命令
打印模式空間的內容,而後清空模式空間
重複上述過程,直到文件結束

 

如圖:

 

 

 

 

打印模式空間(命令 p)

 

 

全部的示例都要用到下面的 employee.txt 文件,請先行建立該文件。

[root@ceph-node5 ~]#  vim employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

使用命令 p,能夠打印當前模式空間的內容。
sed 在執行完命令後會默認打印模式空間的內容,既然如此,那麼你可能會問爲什麼還須要命令 p 呢。
有以下緣由,命令 p 能夠控制只輸出你指定的內容。一般使用 p 時,還須要使用-n 選項來
屏蔽 sed 的默認輸出,不然當執行命令 p 時,每行記錄會輸出兩次。

[root@ceph-node5 ~]# sed 'p' employee.txt
101,John Doe,CEO
101,John Doe,CEO
102,Jason Smith,IT Manager
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
105,Jane Miller,Sales Manager

 

輸出 employee.txt 的內容,只打印一行(cat employee.txt 命令做用相同):

[root@ceph-node5 ~]# sed -n 'p' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 

定址符

 

 

定址符,即[地址1,[地址2]]
是可選項,用來指定處理的起、止行數
不指定定址符時默認處理所有文本
定址符的表示方式可使用行號和正則表達式

 

 例如:

Address:
1、StartLine,EndLine
    好比1,100
    $:最後一行
2、/RegExp/
    /^root/
3、/pattern1/,/pattern2/
    第一次被pattern1匹配到的行開始,至第一次被pattern2匹配到的行結束,這中間的全部行
4、LineNumber
    指定的行
5、StartLine, +N
    從startLine開始,向後的N行;

 

若是在命令前面不指定地址範圍,那麼默認會匹配全部行。 下面的例子,在命令前面指定了地址範圍:

只打印第 2 :

[root@ceph-node5 ~]#  sed -n '2p' employee.txt  
102,Jason Smith,IT Manager

 


打印第 1 至第 4 :

[root@ceph-node5 ~]# sed -n '1,4 p' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer

 


打印第 2 行至最後一行($表明最後一行):

[root@ceph-node5 ~]#  sed -n '2,$ p' employee.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 

修改地址範圍

 

可使用逗號、加號、和波浪號來修改地址範圍。
上面的例子裏面,就已經使用了逗號參與地址範圍的指定。其意思很明瞭: n,m 表明第 n 至第 m 行。
加號+配合逗號使用,能夠指定相的若干行,而不是絕對的幾行。如 n,+m 表示從第 n 行開始後的 m
波浪號~也能夠指定地址範圍。 它指定每次要跳過的行數。如 n~m 表示從第 n 行開始,每次跳過 m 行:

1~2 匹配 1,3,5,7,……
2~2 匹配 2,4,6,8,……
1~3 匹配 1,4,7,10,…..
2~3 匹配 2,5,8,11,…..

 

 只打印奇數行

 

[root@ceph-node5 ~]# sed -n '1~2 p' employee.txt
101,John Doe,CEO
103,Raj Reddy,Sysadmin
105,Jane Miller,Sales Manager

 


模式匹配


一如可使用數字指定地址(或地址範圍),也可使用一個模式(或模式範圍)來匹配,以下面的例子所示。
打印匹配模式"Jane"的行:

[root@ceph-node5 ~]# sed -n '/Jane/ p' employee.txt
105,Jane Miller,Sales Manager

 


打印第一次匹配 Jason 的行至第 4 行的內容:

[root@ceph-node5 ~]#  sed -n '/Jason/,4 p' employee.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer

 



注意:若是開始的 4 行中,沒有匹配到 Jason,那麼 sed 會打印第 4 行之後匹配到 Jason 的內容


打印從第一次匹配 Raj 的行到最後的全部行:

[root@ceph-node5 ~]# sed -n '/Raj/,$ p' employee.txt
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


打印自匹配 Raj 的行開始到匹配 Jane 的行之間的全部內容:

[root@ceph-node5 ~]# sed -n '/Raj/,/Jane/ p' employee.txt
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 



打印匹配 Jason 的行和其後面的兩行:

[root@ceph-node5 ~]#  sed -n '/Jane/,+2 p' employee.txt
105,Jane Miller,Sales Manager

 

 

刪除行

 

命令 d 用來刪除行,須要注意的是它只刪除模式空間的內容,和其餘 sed 命令同樣,命令 d不會修改原始文件的內容。
若是不提供地址範圍, sed 默認匹配全部行,因此下面的例子什麼都不會輸出,由於它匹配了全部行並刪除了它們:

sed 'd' employee.txt


指定要刪除的地址範圍更有用,下面是幾個例子:
只刪除第 2 :

[root@ceph-node5 ~]# sed '2 d' employee.txt
101,John Doe,CEO
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


刪除第 1 至第 4 行:

[root@ceph-node5 ~]# sed '1,4 d' employee.txt
105,Jane Miller,Sales Manager

 

刪除第 2 行至最後一行:

[root@ceph-node5 ~]# sed '2,$ d' employee.txt
101,John Doe,CEO

 


只刪除奇數行:

[root@ceph-node5 ~]#  sed '1~2 d' employee.txt
102,Jason Smith,IT Manager
104,Anand Ram,Developer

 



刪除匹配 Manager 的行:

[root@ceph-node5 ~]#  sed '/Manager/ d' employee.txt
101,John Doe,CEO
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer

 


刪除從第一次匹配 Jason 的行至第 4 行:

[root@ceph-node5 ~]# sed '/Jason/,4 d' employee.txt
101,John Doe,CEO
105,Jane Miller,Sales Manager


若是開頭的 4 行中,沒有匹配 Jason 的行,那麼上述命令將刪除第 4 行之後匹配 Manager的行

 


刪除從第一次匹配 Raj 的行至最後一行:

[root@ceph-node5 ~]# sed '/Raj/,$ d' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager

 


刪除第一次匹配 Jason 的行和緊跟着它後面的兩行:

[root@ceph-node5 ~]# sed '/Jason/,+2 d' employee.txt
101,John Doe,CEO
105,Jane Miller,Sales Manager

 



經常使用的刪除命令示例:
刪除全部空行

[root@ceph-node5 ~]# sed '/^$/ d' employee.txt

 


刪除全部註釋行(假定註釋行以#開頭)

sed '/^#/' employee.txt

 

注意:若是有多個命令, sed 遇到命令 d 時,會刪除匹配到的整行數據,其他的命令將沒法操做被刪除的行。

 

 

把模式空間內容寫到文件中(w 命令)

 

命令 w 能夠把當前模式空間的內容保存到文件中。默認狀況下模式空間的內容每次都會打印到標準輸出,若是要把輸出保存到文件同時不顯示到屏幕上,還須要使用-n 選項。
下面是幾個例子:
employee.txt 的內容保存到文件 output.txt,同時顯示在屏幕上

[root@ceph-node5 ~]# sed 'w output.txt' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

[root@ceph-node5 ~]# cat output.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager


employee.txt 的內容保存到文件 output.txt,但不在屏幕上顯示

[root@ceph-node5 ~]#  sed -n 'w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


只保存第 2 行:

[root@ceph-node5 ~]# sed -n '2 w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
102,Jason Smith,IT Manager


保存第 1 至第 4 行:

[root@ceph-node5 ~]# sed -n '1,4 w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer


保存第 2 行起至最後一行:

[root@ceph-node5 ~]# sed -n '2,$ w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


只保存奇數行:

[root@ceph-node5 ~]# sed -n '1~2 w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
101,John Doe,CEO
103,Raj Reddy,Sysadmin
105,Jane Miller,Sales Manager

 



保存匹配 Jane 的行:

[root@ceph-node5 ~]# sed -n '/Jane/ w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
105,Jane Miller,Sales Manager

 



保存第一次匹配 Jason 的行至第 4 行:

[root@ceph-node5 ~]# sed -n '/Jason/,4 w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer

 

注意: 若是開始的 4 行裏沒有匹配到 Jason,那麼該命令只保存第 4 行之後匹配到 Jason

 


保存第一次匹配 Raj 的行至最後一行:

[root@ceph-node5 ~]#  sed -n '/Raj/,$ w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


保存匹配 Raj 的行至匹配 Jane 的行:

[root@ceph-node5 ~]# sed -n '/Raj/,/Jane/ w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


保存匹配 Jason 的行以及緊跟在其後面的兩行:

[root@ceph-node5 ~]# sed -n '/Jason/,+2 w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer

 

 

 

3、sed 替換命令

 

 流編輯器中最強大的功能就是替換(substitute),

 

sed 替換命令語法

 

 

sed '[address-range|pattern-range] s/original-string/replacement-string/[substitute-flags]' input file

 

 上面提到的語法爲:

 

address-range 或 pattern-range(即地址範圍和模式範圍)是可選的。 若是沒有指定,那麼 sed 將在全部行上進行替換。
s 即執行替換命令 substitute
original-string 是被 sed 搜索而後被替換的字符串,它能夠是一個正則表達式
replacement-string 替換後的字符串
substitute-flags 是可選的,下面會具體解釋

 

請謹記原始輸入文件不會被修改, sed 只在模式空間中執行替換命令,而後輸出模式空間的內容。
下面是一些簡單的替換示例(替換的部分用黑體標明)
Director 替換全部行中的 Manager:

 

[root@ceph-node5 ~]# sed 's/Manager/Director/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Director
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Director

 


只把包含 Sales 的行中的 Manager 替換爲 Director:

[root@ceph-node5 ~]# sed '/Sales/s/Manager/Director/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Director

 

注意: 本例因爲使用了地址範圍限制,因此只有一個 Manager 被替換了

 

 

全局標誌 g

 

 

 

g 表明全局(global) 默認狀況下, sed 至會替換每行中第一次出現的 original-string。若是你要替換每行中出現的全部 original-string,就須要使用 g


用大寫 A 替換第一次出現的小寫字母 a

[root@ceph-node5 ~]#  sed 's/a/A/' employee.txt
101,John Doe,CEO
102,JAson Smith,IT Manager
103,RAj Reddy,Sysadmin
104,AnAnd Ram,Developer
105,JAne Miller,Sales Manager

 



把全部小寫字母 a 替換爲大寫字母 A

[root@ceph-node5 ~]# sed 's/a/A/g' employee.txt
101,John Doe,CEO
102,JAson Smith,IT MAnAger
103,RAj Reddy,SysAdmin
104,AnAnd RAm,Developer
105,JAne Miller,SAles MAnAger


注意:上述例子會在全部行上替換,由於沒有指定地址範圍。

 

 數字標誌(1,2,3 ….)

 

使用數字能夠指定 original-string 出現的次序。 只有第 n 次出現的 original-string 纔會觸發替換。 每行的數字從 1 開始,最大爲 512
好比/11 會替換每行中第 11 次出現的 original-string
下面是幾個例子:
把第二次出現的小寫字母 a 替換爲大寫字母 A

[root@ceph-node5 ~]# sed 's/a/A/2' employee.txt
101,John Doe,CEO
102,Jason Smith,IT MAnager
103,Raj Reddy,SysAdmin
104,Anand RAm,Developer
105,Jane Miller,SAles Manager

 

爲了方便,請先創建以下文件:

[root@ceph-node5 ~]# vim substitute-locate.txt
locate command is used to locate files
locate command uses database to locate files
locate command can also use regex for searching

 



使用剛纔創建的文件,把每行中第二次出現的 locate 替換爲 find:

[root@ceph-node5 ~]#  sed 's/locate/find/2' substitute-locate.txt
locate command is used to find files
locate command uses database to find files
locate command can also use regex for searching

 


注意:第 3 行中 locate 只出現了一次,因此沒有替換任何內容

 

打印標誌 p(print)

 

 

命令 p 表明 print。當替換操做完成後,打印替換後的行。與其餘打印命令相似, sed 中比較有用的方法是和-n 一塊兒使用以抑制默認的打印操做。
只打印替換後的行:

[root@ceph-node5 ~]# sed -n 's/John/Johnny/p' employee.txt
101,Johnny Doe,CEO

 


在以前的數字標誌的例子中,使用/2 來替換第二次出現的 locate。第 3 行中 locate 只出現了一次,因此沒有替換任何內容。使用 p 標誌能夠只打印替換過的兩行。


把每行中第二次出現的 locate 替換爲 find 並打印出來:

[root@ceph-node5 ~]# sed -n 's/locate/find/2p' substitute-locate.txt
locate command is used to find files
locate command uses database to find files

 

 

寫標誌 w

標誌 w 表明 write。當替換操做執行成功後,它把替換後的結果保存的文件中。 多數人更傾向於使用 p 打印內容,而後重定向到文件中。

爲了對 sed 標誌有個完整的描述, 在這裏把這個標誌也提出來了

 

 

只把替換後的內容寫到 output.txt :

[root@ceph-node5 ~]# sed -n 's/John/Johnny/w output.txt' employee.txt
[root@ceph-node5 ~]# cat output.txt
101,Johnny Doe,CEO

 


和以前使用的命令 p 同樣,使用 w 會把替換後的內容保存到文件 output.txt 中。
把每行第二次出現的 locate 替換爲 find,把替換的結果保存到文件中,同時顯示輸入文件全部內容:

[root@ceph-node5 ~]# sed 's/locate/find/2w output.txt' substitute-locate.txt
locate command is used to find files
locate command uses database to find files
locate command can also use regex for searching
[root@ceph-node5 ~]# cat output.txt
locate command is used to find files
locate command uses database to find files

 

 

忽略大小寫標誌 i (ignore)

 

替換標誌 i 表明忽略大小寫。 可使用 i 來以小寫字符的模式匹配 original-string。 該標誌只有 GNU Sed 中才可以使用。
下面的例子不會把 John 替換爲 Johnny,由於 original-string 字符串是小寫形式:

[root@ceph-node5 ~]# sed 's/john/Johnny/' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 



john John 替換爲 Johnny:

[root@ceph-node5 ~]#  sed 's/john/Johnny/i' employee.txt
101,Johnny Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 

 

 

執行命令標誌 e (excuate)


替換標誌 e 表明執行(execute)。該標誌能夠將模式空間中的任何內容當作 shell 命令執行,
並把命令執行的結果返回到模式空間。 該標誌只有 GNU Sed 中才可以使用。
下面是幾個例子:
爲了下面的例子,請先創建以下文件:

[root@ceph-node5 ~]# vim files.txt
/etc/passwd
/etc/group

 



files.txt 文件中的每行前面添加 ls –l 並打擊結果:

[root@ceph-node5 ~]#  sed 's/^/ls -l/' files.txt
ls -l/etc/passwd
ls -l/etc/group

 


files.txt 文件中的每行前面添加 ls –l 並把結果做爲命令執行:

[root@ceph-node5 ~]#  sed 's/^/ls -l /e' files.txt
-rw-r--r--. 1 root root 890 Oct 29 16:20 /etc/passwd
-rw-r--r--. 1 root root 457 Oct 29 16:20 /etc/group

 



使用替換標誌組合


根據須要能夠把一個或多個替換標誌組合起來使用。
下面的例子將把每行中出現的全部 Manager manager 替換爲 Director。而後把替換後的內容打印到屏幕上,同時把這些內容保存到 output.txt 文件中。
使用 g,i,p w 的組合:

[root@ceph-node5 ~]# sed -n 's/manager/Director/igpw output.txt' employee.txt
102,Jason Smith,IT Director
105,Jane Miller,Sales Director
[root@ceph-node5 ~]# cat output.txt
102,Jason Smith,IT Director
105,Jane Miller,Sales Director

 

 

 

 

sed 替換命令分界符


上面全部例子中,咱們都是用了 sed 默認的分界符/,s/original-string/replacement-string/g

若是在 original-string replacement-string 中有/,那麼須要使用反斜槓\來轉義。爲了便於示例,請先創建下面文件:

 

[root@ceph-node5 ~]# vim path.txt
reading /usr/local/bin directory

 


限制使用 sed /usr/local/bin 替換爲/usr/bin。 在下面例子中, sed 默認的分界符/都被\轉義了:

[root@ceph-node5 ~]# sed 's/\/usr\/local\/bin/\/usr\/bin/' path.txt
reading /usr/bin directory


這很難看。 若是要替換一個很長的路徑,每一個/前面都使用\轉義,會顯得很混亂。幸運的是,你可使用任何一個字符做爲 sed 替換命令的分界符,如 | ^ @ 或者 !
下面的全部例子都比較易讀。 這裏再也不顯示下面例子的結果,由於它們的結果和上面的例子是相同的。 我我的比較傾向於使用@或者!來替換路徑,但使用什麼看你本身的偏好了。

sed 's|/usr/local/bin|/usr/bin|' path.txt
sed 's^/usr/local/bin^/usr/bin^' path.txt
sed 's@/usr/local/bin@/usr/bin@' path.txt
sed 's!/usr/local/bin!/usr/bin!' path.txt

 

 

 

單行內容上執行多個命令


一如以前所說, sed 執行的過程是讀取內容、執行命令、打印結果、重複循環。 其中執行命令部分,能夠由多個命令執行, sed 將一個一個地依次執行它們。
例如,你有兩個命令, sed 將在模式空間中執行第一個命令,而後執行第二個命令。

若是第一個命令改變了模式空間的內容,第二個命令會在改變後的模式空間上執行(此時模式空間的內容已經不是最開始讀取進來的內容了)
下面的例子演示了在模式空間內執行兩個替換命令的過程:
Developer 替換爲 IT Manager,而後把 Manager 替換爲 Director:

[root@ceph-node5 ~]# sed '{
> s/Developer/IT Manager/
> s/Manager/Director/
>  }' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Director
103,Raj Reddy,Sysadmin
104,Anand Ram,IT Director
105,Jane Miller,Sales Director

 


咱們來分析下第 4 行的執行過程:

1.讀取數據: 在這一步, sed 讀取內容到模式空間,此時模式空間的內容爲:104,Anand Ram,Developer
2.執行命令: 第一個命令, s/Developer/IT Manager/執行後,模式空間的內容爲:104,Anand Ram,IT Manager
如今在模式空間上執行第二個命令 s/Manager/Director/,執行後,模式空間內容爲:104,Anand Ram,IT Director
謹記: sed 在第一個命令執行的結果上,執行第二個命令。
3.打印內容:打印當前模式空間的內容,以下:104,Anand Ram,IT Director
4.重複循環: 移動的輸入文件的下一行,而後重複執行第一步,即讀取數據 

 

 

&的做用——獲取匹配到的模式


當在 replacement-string 中使用&時,它會被替換成匹配到的 original-string 或正則表達式,這是個頗有用的東西。
看下面示例:
給僱員 ID(即第一列的 3 個數字)加上[ ],101 改爲[101]

[root@ceph-node5 ~]# sed 's/^[0-9][0-9][0-9]/[&]/g' employee.txt
[101],John Doe,CEO
[102],Jason Smith,IT Manager
[103],Raj Reddy,Sysadmin
[104],Anand Ram,Developer
[105],Jane Miller,Sales Manager

 



把每一行放進< >中:

[root@ceph-node5 ~]# sed 's/^.*/<&>/' employee.txt
<101,John Doe,CEO>
<102,Jason Smith,IT Manager>
<103,Raj Reddy,Sysadmin>
<104,Anand Ram,Developer>
<105,Jane Miller,Sales Manager>

 

 

分組替換(單個分組)


跟在正則表達式中同樣, sed 中也可使用分組。分組以\(開始,以\)結束。 分組能夠用在回溯引用中。
回溯引用即從新使用分組所選擇的部分正則表達式, 在 sed 替換命令的 replacement-string

中和正則表達式中,均可以使用回溯引用。
單個分組:

[root@ceph-node5 ~]# sed 's/\([^,]*\).*/\1/g' employee.txt
101
102
103
104
105

 



上面例子中:

正則表達式\([^,]*\)匹配字符串從開頭到第一個逗號之間的全部字符(並將其放入第一個分組中)
replacement-string 中的\1 將替代匹配到的分組
g 便是全局標誌

 

下面這個例子只會顯示/etc/passwd 的第一列,即用戶名:

[root@ceph-node5 ~]#  sed 's/\([^:]*\).*/\1/' /etc/passwd

 


下面的例子,若是單詞第一個字符爲大寫,那麼會給這個大寫字符加上()

[root@ceph-node5 ~]# echo "The Geek Stuff"|sed 's/\(\b[A-Z]\)/\(\1\)/g'
(T)he (G)eek (S)tuff

 


請先創建下面文件,以便下面的示例使用:

[root@ceph-node5 ~]# vim numbers.txt
1
12
123
1234
12345
123456

 



格式化數字,增長其可讀性:

[root@ceph-node5 ~]# sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' numbers.txt
1
12
123
1,234
12,345
123,456

 

 

分組替換(多個分組)


你可使用多個\(\)劃分多個分組,使用多個分組時,須要在 replacement-string 中使用\n來指定第 n 個分組。以下面的示例。
只打印第一列(僱員 ID)和第三列(僱員職位):

[root@ceph-node5 ~]#  sed 's/^\([^,]*\),\([^,]*\),\([^,]*\)/\1,\3/' employee.txt
101,CEO
102,IT Manager
103,Sysadmin
104,Developer
105,Sales Manager


在這個例子中,能夠看到, original-string 中,劃分了 3 個分組,以逗號分隔。

([^,]*\) 第一個分組,匹配僱員 ID,爲字段分隔符
([^,]*\) 第二個分組,匹配僱員姓名,爲字段分隔符
([^,]*\) 第三個分組,匹配僱員職位,爲字段分隔符,
上面的例子演示瞭如何使用分組 \
1 表明第一個分組(僱員 ID),出如今第一個分組以後的逗號 \3 表明第二個分組(僱員職位)

 

注意: sed 最多能處理 9 個分組,分別用\1 \9 表示。

交換第一列(僱員 ID)和第二列(僱員姓名)

[root@ceph-node5 ~]# sed 's/^\([^,]*\),\([^,]*\),\([^,]*\)/\2,\1,\3/' employee.txt
John Doe,101,CEO
Jason Smith,102,IT Manager
Raj Reddy,103,Sysadmin
Anand Ram,104,Developer
Jane Miller,105,Sales Manager

 

 

 

 

GNU Sed 專有的替換標誌

 

 


下面的標誌,只有 GNU 版的 sed 才能使用。 它們能夠用在替換命令中的 replacement-string裏面.

 

 

\l 標誌

 

 


當在 replacement-string 中使用\l 標誌時,它會把緊跟在其後面的字符當作小寫字符來處理。
如你所知,下面的例子將把 John 換成 JOHNNY:

[root@ceph-node5 ~]# sed 's/John/JOHNNY/' employee.txt  
101,JOHNNY Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


下面的例子,在 replacement-string 中的 H 前面放置了\l 標誌,它會把 JOHNNY 中的 H 換成小寫的 h:

[root@ceph-node5 ~]# sed -n 's/John/JO\lHNNY/p' employee.txt
101,JOhNNY Doe,CEO

 

 

\L 標誌

 

 

 


當在 replacement-string 中使用\l 標誌時,它會把後面全部的字符都當作小寫字符來處理。
下面的例子,在 replacement-string 中的 H 前面放置了\L 標誌,它會把 H 和它後面的全部字符都換成小寫:

[root@ceph-node5 ~]#  sed -n 's/John/JO\LHNNY/p' employee.txt
101,JOhnny Doe,CEO

 

\u 標誌


\l 相似,只不過是把字符換成大寫。 當在 replacement-string 中使用\u 標誌時,它會把緊跟在其後面的字符當作大寫字符來處理。

下面的例子中, replacement-string 裏面的 h 前面有\u 標誌,因此 h 將被換成大寫的 H:

[root@ceph-node5 ~]#  sed -n 's/John/jo\uhnny/p' employee.txt
101,joHnny Doe,CEO

 

 

 

 

 

 

\U 標誌

 


當在 replacement-string 中使用\U 標誌時,它會把後面全部的字符都當作大寫字符來處理。
下面的例子中, replacement-string 裏面的 h 前面有\U 標誌,因此 h 及其之後的全部字符,都將被換成大寫:

[root@ceph-node5 ~]# sed -n 's/John/jo\Uhnny/p' employee.txt
101,joHNNY Doe,CEO

 

 

 

\E 標誌


\E 標誌須要和\U \L 一塊兒使用,它將關閉\U \L 的功能。下面的例子將把字符串"Johnny Boy"的每一個字符都以大寫的形式打印出來,

由於在 replacement-string 前面使用了\U 標誌:

[root@ceph-node5 ~]# sed -n 's/John/\UJohnny Boy/p' employee.txt
101,JOHNNY BOY Doe,CEO

 


下面將把 John 換成 JOHNNY Boy:

[root@ceph-node5 ~]# sed -n 's/John/\UJohnny\E Boy/p' employee.txt
101,JOHNNY Boy Doe,CEO

 

這個例子只把 Johnny 顯示爲大寫,由於在 Johnny 後面使用了\E 標誌(關閉了\U 的功能)替換標誌的用法

上面的例子僅僅展現了這些標誌的用法和功能。 然而,若是你使用的是具體的字符串,那麼這些選項未必有什麼做用,由於你能夠在須要的地方寫出精確的字符串,

而不須要使用這些標誌進行轉換。和分組配合使用時,這些選項就顯得頗有用了。

前面例子中咱們已經學會了如何使用分組調換第一列和第三列的位置。 使用上述標誌,能夠把整個分組轉換爲小寫或大寫。
下面的例子,僱員 ID 都顯示爲大寫,職位都顯示爲小寫:

[root@ceph-node5 ~]# sed 's/\([^,]*\),\([^,]*\),\([^,]*\)/\U\2\E,\1,\L\3/' employee.txt
JOHN DOE,101,ceo
JASON SMITH,102,it manager
RAJ REDDY,103,sysadmin
ANAND RAM,104,developer
JANE MILLER,105,sales manager

 


這個例子中:

\U\2\E 把第二個分組轉換爲大寫,而後用\E 關閉轉換
\L\3 把第三個分組轉換爲小寫

 

 

 

 

 

 

 

4、簡單正則表達式


從以上案例中咱們不難發現,咱們編寫的腳本指令須要指定一個地址來決定操做範圍,若是不指定則默認對文件的全部行操做。

 

如:sed   'd'     test.txt              將刪除 test.txt 的全部行,而'2d'
則僅刪除第二行。
1.爲 sed 指令肯定操做地址:
number              指定輸入文件的惟一行號。
first~step       以 first 開始,並指定操做步長爲 step,如 1~2,指定第一行,
第三行,第五行... 爲操做地址。
[jacob@localhost ~] #sed   -n   '1~2p'   test.txt              打印文件的奇數行。
DEVICE=eth0
BOOTPROTO=static
NETMASK=255.255.255.0
2~5,則能夠指定第二行開始,每 5 行匹配一次操做地址。
$                     匹配文件的最後一行。
/regexp/         //中間包含的是正則表達式,經過正則表達式匹配操做地址。
注: //空的正則表達式,匹配最近一次正則表達式的匹配地址,會在後面使用看出效果。
\cregexpc         匹配擴展正則表達式,c 字符可使用任意字符替代。
addr1,addr2       匹配從操做地址 1 到操做地址 2 的全部行。
[jacob@localhost ~] #sed   '2,8d'   test.txt              #刪除 28 中間的全部行。
DEVICE=eth0
addr1,+N              匹配地址 1 以及後面的 N 行內容。

 



2.正則表達式概述(對你要找內容的一種描述)

char                     字符自己就匹配字符自己,如/abc/就是定位包含 abc的行。
*                     匹配前面表達式出現了 0 或若干次,如/a*/能夠幫你找到a,aa,aaa,... ...等等。
\+                     相似於*,但匹配前面表達式的 1 次或屢次,這屬於擴展正則表達式。
\?                     相似於*,但匹配前面表達式的 0 次或 1 次,這屬於擴展正則表達式。
\{i\}                相似於*,但匹配前面表達式的 i 次(i 爲整數),如: a\{3\}能夠幫你找到 aaa。
\{i,j\}            匹配前面表達式的 i 到 j 次,如 a\{1,2\}能夠幫你找到 a 或aa 或 aaa。
\{i,\}              匹配前面表達式至少 i 次。
\( \)                將\( \)內的模式存儲在保留空間。最多能夠存儲 9 個獨立子模式,
                     可經過轉義\1 至\9 重複保留空間的內容至此點。
\n                     轉義\1 至\9 重複保留空間的內容至此點。
例:test.txt 的內容爲 ssttss
grep '\(ss\)tt\1' test.txt                     \1 表示將 ss 重複在 tt 後面
該 grep 命令等同於grep   ssttss   test.txt       在 test.txt 文件中找 ssttss
.                     (點)匹配任意字符。
^                     匹配行的開始,如^test       將匹配全部以 test 開始的行。
$                     匹配行的結尾,如 test$       將匹配全部以 test 結尾的行。
[]                   匹配括號中的任意單個字符,如 a[nt]       將匹配 an 或at。
[^]                 匹配不包含在[]中的字符,如[^a-z]       將匹配除 a-z之外的字符。
\n                   匹配換行符。
\char              轉義特殊字符,如\*,就是匹配字面意義上的星號。

 

 

行的開頭 ( ^ )

^ 匹配每一行的開頭


顯示以 103 開頭的行:

[root@ceph-node5 ~]# sed -n '/^103/ p' employee.txt
103,Raj Reddy,Sysadmin

 


只有^出如今正則表達式開頭時,它才匹配行的開頭。 因此, ^N 匹配全部以 N 開頭的行。

 


行的結尾
( $ )


$匹配行的結尾。


顯示以字符
r 結尾的行:

[root@ceph-node5 ~]# sed -n '/r$/ p' employee.txt
102,Jason Smith,IT Manager
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 

 單個字符 ( . )

元字符點 . 匹配除換行符以外的任意單個字符

.匹配單個字符
.. 匹配兩個字符
...匹配三個字符
....以此類推

 

 

匹配 0 次或屢次 ( * )


星號*匹配 0 個或多個其前面的字符。如: 1* 匹配 0 個或多個 1
先創建下面文件:

[root@ceph-node5 ~]# cat log.txt
log: input.txt
log:
log: testing resumed
log:
log:output created

 


假設你想查看那些包含 log 而且後面有信息的行, log 和信息之間可能有 0 個或多個空格,同時不想查看那些 log:後面沒有任何信息的行。
顯示包含
log:而且 log 後面有信息的行, log 和信息之間可能有空格:

[root@ceph-node5 ~]#  sed -n '/log: *./p' log.txt
log: input.txt
log: testing resumed
log:output created

 

注意: 上面例子中,後面的點.是必需的,若是沒有, sed 只會打印全部包含 log 的行。


匹配一次或屢次
( \+ )


「\+」匹配一次或屢次它前面的字符,例如 空格\+ 「 \+」匹配至少一個或多個空格。
仍舊使用
log.txt 這個文件來做示例。
顯示包含
log:而且 log:後面有一個或多個空格的全部行:

[root@ceph-node5 ~]# sed -n '/log: \+/ p' log.txt
log: input.txt
log: testing resumed

 



注意:這個例子既沒有匹配只包含 log:的行,也沒有匹配 log:output craeted 這一行,由於 log:後面沒有空格。


零次或一次匹配
( \? )


\?匹配 0 次或一次它前面的字符。 如:

[root@ceph-node5 ~]# sed -n '/log: \+/ p' log.txt
log: input.txt
log: testing resumed
[root@ceph-node5 ~]# sed -n '/log: \?/ p' log.txt
log: input.txt
log:
log: testing resumed
log:
log:output created

 

 

轉義字符 ( \ )

 

 

若是要在正則表達式中搜尋特殊字符(:*,.),必需使用\來轉義它們。

sed -n '/127\.0\.0\.1/ p' /etc/hosts
127.0.0.1 localhost

 

字符集 ( [0-9] )

 

 

字符集匹配方括號中出現的任意一個字符。
匹配包含
23 或者 4 的行:

[root@ceph-node5 ~]# sed -n '/[234]/ p' employee.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer

 


在方括號中,可使用鏈接符-指定一個字符範圍。如[0123456789]能夠用[0-9]表示,字母能夠用[a-z],[A-Z]表示,等等。
匹配包含
23 或者 4 的行(另外一種方式):

[root@ceph-node5 ~]# sed -n '/[2-4]/ p' employee.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer

 

 或操做符 ( | )


管道符號|用來匹配兩邊任意一個子表達式。 子表達式 1|子表達式 2 匹配子表達式 1 或者子表達式 2
打印包含 101 或者包含 102 的行:

[root@ceph-node5 ~]# sed -n '/101\|102/ p' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager

 


須要注意, | 須要用\轉義。
打印包含數字 2~3 或者包含 105 的行:

[root@ceph-node5 ~]# sed -n '/[2-3]\|105/ p' employee.txt
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
105,Jane Miller,Sales Manager

 

 

精確匹配 m ( {m} )




正則表達式後面跟上{m}標明精確匹配該正則 m 次。
請先創建以下文件:

[root@ceph-node5 ~]# vim numbers.txt
1
12
123
1234
12345
123456

 


打印包含任意數字的行(這個命令將打印全部行):

[root@ceph-node5 ~]# sed -n '/[0-9]/ p' numbers.txt
1
12
123
1234
12345
123456

 


打印包含 5 個數字的行:

[root@ceph-node5 ~]# sed -n '/^[0-9]\{5\}$/ p' numbers.txt
12345

 


注意這裏必定要有開頭和結尾符號,即^$,而且{}都要用\轉義

 

匹配 m n ( {m,n} ):


正則表達式後面跟上{m,n}代表精確匹配該正則至少 m,最多 n 次。 m n 不能是負數,而且要小於 255.
打印由 3 5 個數字組成的行:

[root@ceph-node5 ~]# sed -n '/^[0-9]\{3,5\}$/ p' numbers.txt
123
1234
12345

 



正則表達式後面跟上{m,}代表精確匹配該正則至少 m,最多不限。 (一樣,若是是{,n}代表最多匹配 n 次,最少一次)

字符邊界 ( \b )

\b 用來匹配單詞開頭(\bxx)或結尾(xx\b)的任意字符,所以\bthe\b 將匹配 the,但不匹配 they。\bthe 將匹配 the they.
請先創建以下文件:

[root@ceph-node5 ~]# vim words.txt
word matching using: the
word matching using: thethe
word matching using: they

 

 

匹配包含 the 做爲整個單詞的行:

[root@ceph-node5 ~]# sed -n '/\bthe\b/ p' words.txt
word matching using: the

 


注意:若是沒有後面那個\b,將匹配全部行。
匹配全部以 the 開頭的單詞:

[root@ceph-node5 ~]# sed -n '/\bthe/ p' words.txt
word matching using: the
word matching using: thethe
word matching using: they

 

回溯引用 ( \n )

使用回溯引用,能夠給正則表達式分組,以便在後面引用它們。
只匹配重複 the 兩次的行:

[root@ceph-node5 ~]# sed -n '/\(the\)\1/ p' words.txt
word matching using: thethe

 


同理, 」\([0-9]\)\1」 匹配連續兩個相同的數字,如 11,22,33 …..

 

sed 替換中使用正則表達式

 

下面是一些使用正則表達式進行替換的例子。
employee.txt 中每行最後兩個字符替換爲」,Not Defined」:

[root@ceph-node5 ~]# sed -n 's/..$/,Not Defined/ p' employee.txt
101,John Doe,C,Not Defined
102,Jason Smith,IT Manag,Not Defined
103,Raj Reddy,Sysadm,Not Defined
104,Anand Ram,Develop,Not Defined
105,Jane Miller,Sales Manag,Not Defined

 


刪除以 Manager 開頭的行的後面的全部內容:

[root@ceph-node5 ~]# sed 's/^Manager.*//' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


這個示例好像有點問題啊,我以爲應該是 sed ‘s/^Manager.*/Manager/’
刪除全部以#開頭的行:

[root@ceph-node5 ~]#  sed -e 's/#.*// ; /^$/ d' employee.txt 
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager


我以爲用 sed ‘/^#/ d’ 更好
創建下面的 test.html 文件:

[root@ceph-node5 ~]# vim test.html
<html><body><h1>Hello World!</h1></body></html>

 


清除 test.html 文件中的全部 HTML 標籤:

[root@ceph-node5 ~]# sed 's/<[^>]*>//g' test.html
Hello World!

 


刪除全部註釋行和空行:

[root@ceph-node5 ~]# sed -e 's/#.*// ; /^$/ d' /etc/profile

 


只刪除註釋行,保留空行:

[root@ceph-node5 ~]# sed '/#.*/ d' /etc/profile 

 

使用 sed 能夠把 DOS 的換行符(CR/LF)替換爲 Unix 格式。 當把 DOS 格式的文件拷到 Unix 上,你會發現,每行結尾都有\r\n .
使用 sed DOS 格式的文件轉換爲 Unix 格式:

sed ‘s/.$//’ filename 

 

 

 

5、執行 sed

 

單行內執行多個 sed 命令

 

 

 

1. 使用多命令選項 –e
多命令選項-e 使用方法以下:

sed –e 'command1' –e 'command2' –e 'command3'

 


/etc/passwd 文件中,搜索 rootnobody mail:

[root@ceph-node5 ~]# sed -n -e '/^root/ p' -e '/^nobody/ p' -e '/^mail/ p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin

 




2. 使用\ 折行執行多個命令


在執行很長的命令,好比使用
-e 選項執行多個 sed 命令時,可使用\來把命令折到多行

[root@ceph-node5 ~]# sed -n -e '/^root/ p' \
> -e '/^nobody/ p' \
> -e '/^mail/ p' \
> /etc/passwd
root:x:0:0:root:/root:/bin/bash
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin

 


3. 使用{ }把多個命令組合
若是要執行不少
sed 命令,可使用{ }把他們組合起來執行,如:

[root@ceph-node5 ~]# sed -n '{
> /^root/ p
> /^nobody/ p
> /^mail/ p
> }' /etc/passwd
root:x:0:0:root:/root:/bin/bash
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin

 

 

 

sed 腳本文件

若是用重複使用一組 sed 命令,那麼能夠創建 sed 腳本文件,裏面包含全部要執行的 sed 命令,而後用-f 選項來使用。
首先創建下面文件,裏面包含了全部要執行的
sed 命令。 前面已經解釋過各個命令的含義,
如今你應該知道全部命令的意思了。

[root@ceph-node5 ~]# vim mycommands.sed
s/\([^,]*\),\([^,]*\),\(.*\).*/\2,\1, \3/g
s/^.*/<&>/
s/Developer/IT Manager/
s/Manager/Director/

 

如今執行腳本里面的命令:

[root@ceph-node5 ~]# sed -f mycommands.sed employee.txt
<John Doe,101, CEO>
<Jason Smith,102, IT Director>
<Raj Reddy,103, Sysadmin>
<Anand Ram,104, IT Director>
<Jane Miller,105, Sales Director>

 

sed 註釋

 

sed 註釋以#開頭。由於 sed 是比較晦澀難懂的語言,因此你如今寫下的 sed 命令,時間一長,再看時就不那麼容易理解了。

所以,建議把寫腳本時的初衷做爲註釋,寫到腳本里面。 以下所示:

[root@ceph-node5 ~]#  vim mycommands.sed
#交換第一列和第二列 s/\([^,]*\),\([^,]*\),\(.*\).*/\2,\1, \3/g #把整行內容放入<>中 s/^.*/<&>/ #把 Developer 替換爲 IT Manager s/Developer/IT Manager/ #把 Manager 替換爲 Director s/Manager/Director/

 

 


注意: 若是 sed 腳本第一行開始的兩個字符是#n 的話, sed 會自動使用-n 選項(即不自動打印模式空間的內容)

 

 

sed 當作命令解釋器使用

 


一如你能夠把命令放進一個 shell 腳本中,而後調用腳本名稱來執行它們同樣,你也能夠把sed 用做命令解釋器。

要實現這個功能,須要在 sed 腳本最開始加入"#!/bin/sed –f",以下所示:

[root@ceph-node5 ~]#  vim myscript.sed
#!/bin/sed -f
#交換第一列和第二列
s/\([^,]*\),\([^,]*\),\(.*\).*/\2,\1, \3/g
#把整行內容放入<>中
s/^.*/<&>/
#把 Developer 替換爲 IT Manager
s/Developer/IT Manager/
#把 Manager 替換爲 Director
s/Manager/Director/

 

如今,給這個腳本加上可執行權限,而後直接在命令行調用它:

[root@ceph-node5 ~]#  chmod u+x myscript.sed
[root@ceph-node5 ~]#  ./myscript.sed employee.txt
<John Doe,101, CEO>
<Jason Smith,102, IT Director>
<Raj Reddy,103, Sysadmin>
<Anand Ram,104, IT Director>
<Jane Miller,105, Sales Director>

 


也能夠指定-n 選項來屏蔽默認輸出:

[root@ceph-node5 ~]# vim testscript.sed
#!/bin/sed -nf
/root/ p
/nobody/ p
/mail/ p

 



而後加上可執行權限,執行:

[root@ceph-node5 ~]# chmod u+x testscript.sed
[root@ceph-node5 ~]# ./testscript.sed /etc/passwd
root:x:0:0:root:/root:/bin/bash
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin

 


處於測試目的,把 testscript.sed 裏面的-n 去掉,而後再執行一次, 觀察它是如何運行的。
重要提示
:使用-n 時,必須是-nf.若是你寫成-fn,執行腳本時就會得到下面的錯誤:

[root@ceph-node5 ~]#  ./testscript.sed /etc/passwd
/bin/sed: couldn't open file n: No such file or directory

 

 

 

直接修改輸入文件

目前爲止,你知道 sed 默認不會修改輸入文件, 它只會把輸出打印到標準輸出上。 當想保存結果時,把輸出重定向到文件中(或使用 w 命令)
執行下面的例子以前,先備份一下
employee.txt 文件:

[root@ceph-node5 ~]# cp employee.txt{,.orig}

 


爲了修改輸入文件,一般方法是把輸出重定向到一個臨時文件,而後重命名該臨時文件:

[root@ceph-node5 ~]# sed 's/John/Johnny/' employee.txt > new-employee.txt  
[root@ceph-node5 ~]# mv new-employee.txt employee.txt

 


相比這種傳統方法,能夠在 sed 命令中使用-i 選項,使 sed 能夠直接修改輸入文件:
在原始文件 employee.txt 中,把 John 替換爲 Johnny:

[root@ceph-node5 ~]# sed -i 's/John/Johnny/' employee.txt
[root@ceph-node5 ~]# cat employee.txt
101,Johnnyny Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


再次提醒: -i 會修改輸入文件。 或許這正是你想要的,可是務必當心。 一個保護性的措施是,在-i 後面加上備份擴展,這一 sed 就會在修改原始文件以前,備份一份。
在原始文件
employee.txt 中,把 John 替換爲 Johnny,但在替換前備份 employee.txt:

[root@ceph-node5 ~]# sed -ibak 's/John/Johnny/' employee.txt

 


備份的文件以下:

[root@ceph-node5 ~]# cat employee.txtbak
101,Johnnyny Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


修改後的原始文件爲:

[root@ceph-node5 ~]# cat employee.txt
101,Johnnynyny Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


除了使用-i,也可使用完整樣式 –in-place.下面兩個命令是等價的:

[root@ceph-node5 ~]# sed -ibak 's/John/Johnny/' employee.txt 
[root@ceph-node5 ~]# sed -in-place=bak 's/John/Johnny/' employee.txt

 



最後,爲了繼續下面的例子,把原來的 employee.txt 還原回去:

cp employee.txt.orig employee.txt

 



6、sed 附加命令

 

追加命令(命令 a)

 



使用命令 a 能夠在指定位置的後面插入新行。
語法:

sed '[address] a the-line-to-append' input-file

 


在第 2 行後面追加一行(原文這裏可能有問題,沒有寫明行號):

[root@ceph-node5 ~]# sed '2 a 203,Jack Johnson,Engineer' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
203,Jack Johnson,Engineer
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


employee.txt 文件結尾追加一行:

[root@ceph-node5 ~]# sed '$ a 106,Jack Johnson,Engineer' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
106,Jack Johnson,Engineer

 



在匹配
Jason 的行的後面追加兩行:

[root@ceph-node5 ~]# sed '/Jason/a\
> 203,Jack Johnson,Engineer\
> 204,Mark Smith,Sales Engineer' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
203,Jack Johnson,Engineer
204,Mark Smith,Sales Engineer
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


追加多行之間能夠用\n 來換行,這樣就不用折行了,上面的命令等價於:
sed '/Jason/a 203,Jack Johnson,Engineer\n204,Mark Smith,Sales Engineer' employee.txt

 

 

插入命令(命令 i)


插入命令 insert 命令和追加命令相似,只不過是在指定位置以前插入行。
語法:

 sed '[address] i the-line-to-insert' input-file

 


employee.txt 的第 2 行以前插入一行:

[root@ceph-node5 ~]# sed '2 i 203,Jack Johnson,Engineer' employee.txt
101,John Doe,CEO
203,Jack Johnson,Engineer
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


employee.txt 最後一行以前,插入一行:

[root@ceph-node5 ~]# sed '$ i 108,Jack Johnson,Engineer' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
108,Jack Johnson,Engineer
105,Jane Miller,Sales Manager

 


sed
也能夠插入多行。
在匹配
Jason 的行的前面插入兩行:

sed '/Jason/i\
203,Jack Johnson,Engineer\
204,Mark Smith,Sales Engineer' employee.txt
101,John Doe,CEO
203,Jack Johnson,Engineer
204,Mark Smith,Sales Engineer
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


修改命令(命令 c)
修改命令 change 能夠用新行取代舊行。
語法:

sed '[address] c the-line-to-insert' input-file

 



用新數據取代第 2 :

[root@ceph-node5 ~]# sed '2 c 202,Jack,Johnson,Engineer' employee.txt
101,John Doe,CEO
202,Jack,Johnson,Engineer
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


這裏命令 c 等價於替換: $ sed '2s/.*/202,Jack,Johnson,Engineer/' employee.txt
sed 也能夠用多行來取代一行。
用兩行新數據取代匹配
Raj 的行:

[root@ceph-node5 ~]# sed '/Raj/c\
> 203,Jack Johnson,Engineer\
> 204,Mark Smith,Sales Engineer' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
203,Jack Johnson,Engineer
204,Mark Smith,Sales Engineer
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


命令 a、 i 和 c 組合使用


命令 ai c 能夠組合使用。下面的例子將完成三個操做:

a 在"Jason"後面追加"Jack Johnson"
i 在"Jason"前面插入"Mark Smith"
c 用"Joe Mason"替代"Jason"

 


以下:

[root@ceph-node5 ~]# sed '/Jason/ {a\
> 204,Jack Johnson,Engineer
> i\
> 202,Mark Smith,Sales Engineer
> c\
> 203,Joe Mason,Sysadmin
> }' employee.txt
101,John Doe,CEO
202,Mark Smith,Sales Engineer
203,Joe Mason,Sysadmin
204,Jack Johnson,Engineer
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 

 

打印不可見字符(命令 l)

 


命令 l 能夠打印不可見的字符,好比製表符\t,行尾標誌$等。
請先創建下面文件以便用於後續測試,請確保字段之間使用製表符
(Tab )分開:

[root@ceph-node5 ~]# vim  tabfile.txt
fname First Name
lname Last Name
mname Middle Name

 

 

使用命令 l,把製表符顯示爲\t,行尾標誌顯示爲 EOL:

[root@ceph-node5 ~]# sed -n 'l' tabfile.txt
fname First Name$
lname Last Name$
mname Middle Name$

 


若是在 l 後面指定了數字,那麼會在第 n 個字符處使用一個不可見自動折行,效果以下:

[root@ceph-node5 ~]# sed -n 'l 20' employee.txt
101,John Doe,CEO$
102,Jason Smith,IT \
Manager$
103,Raj Reddy,Sysad\
min$
104,Anand Ram,Devel\
oper$
105,Jane Miller,Sal\
es Manager$

 


這個功能只有 GNU sed 纔有。

 

打印行號(命令=)


命令=會在每一行後面顯示該行的行號。

打印全部行號:

[root@ceph-node5 ~]#  sed '=' employee.txt
1
101,John Doe,CEO
2
102,Jason Smith,IT Manager
3
103,Raj Reddy,Sysadmin
4
104,Anand Ram,Developer
5
105,Jane Miller,Sales Manager

 


提示: 把命令=和命令 N 配合使用,能夠把行號和內容顯示在同一行上(下文解釋)
只打印
1,2,3 行的行號:

[root@ceph-node5 ~]# sed '1,3 =' employee.txt
1
101,John Doe,CEO
2
102,Jason Smith,IT Manager
3
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 


打印包含關鍵字」Jane」的行的行號,同時打印輸入文件中的內容:

[root@ceph-node5 ~]#  sed '/Jane/ =' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
5
105,Jane Miller,Sales Manager

 


若是你想只顯示行號但不顯示行的內容,那麼使用-n 選項來配合命令=:

[root@ceph-node5 ~]# sed -n '/Raj/ =' employee.txt
3

 


打印文件的總行數:

[root@ceph-node5 ~]# sed -n '$ =' employee.txt
5

 

 

轉換字符(命令 y)

 


命令 y 根據對應位置轉換字符。好處之一即是把大寫字符轉換爲小寫,反之亦然。
下面例子中,將把
a 換爲 Ab 換爲 Bc 換爲 C,以此類推:

[root@ceph-node5 ~]#  sed 'y/abcde/ABCDE/' employee.txt
101,John DoE,CEO
102,JAson Smith,IT MAnAgEr
103,RAj REDDy,SysADmin
104,AnAnD RAm,DEvElopEr
105,JAnE MillEr,SAlEs MAnAgEr

 


把全部小寫字符轉換爲大寫字符:

[root@ceph-node5 ~]# sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' employee.txt
101,JOHN DOE,CEO
102,JASON SMITH,IT MANAGER
103,RAJ REDDY,SYSADMIN
104,ANAND RAM,DEVELOPER
105,JANE MILLER,SALES MANAGER

 

操做多個文件

 


以前的例子都只操做了單個文件, sed 也能夠同時處理多個文件。
/etc/passwd 中搜索 root 並打印出來:

[root@ceph-node5 ~]# sed -n '/root/ p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

 


/etc/group 中搜索 root 並打印出來:

[root@ceph-node5 ~]# sed -n '/root/ p' /etc/group
root:x:0:

 


同時在/etc/passwd /etc/group 中搜索 root:

[root@ceph-node5 ~]# sed -n '/root/ p' /etc/passwd /etc/group
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
root:x:0:

 


 退出 sed(命令 q)


命令 q 終止正在執行的命令並退出 sed
以前提到,正常的
sed 執行流程是:讀取數據、執行命令、打印結果、重複循環。
sed 遇到 q 命令,便馬上退出,當前循環中的後續命令不會被執行,也不會繼續循環。
打印第
1 行後退出:

[root@ceph-node5 ~]# sed 'q' employee.txt
101,John Doe,CEO

 


打印第 5 行後退出,即只打印前 5 行:

 

[root@ceph-node5 ~]# sed '5 q' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 

 



打印全部行,直到遇到包含關鍵字 Manager 的行:

[root@ceph-node5 ~]# sed '/Manager/ q' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager

 


注意: q 命令不能指定地址範圍(或模式範圍),只能用於單個地址(或單個模式)

 

 

從文件讀取數據(命令 r)

在處理輸入文件是,命令 r 會從另一個文件讀取內容,並在指定的位置打印出來。

下面的例子將讀取 log.txt 的內容,並在打印 employee.txt 最後一行以後,把讀取的內容打印出來。事實上它把 employee.txt log.txt 合併而後打印出來。

[root@ceph-node5 ~]# sed '$ r log.txt' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
log: input.txt
log:
log: testing resumed
log:
log:output created

 


也能夠給命令 r 指定一個模式。下面的例子將讀取 log.txt 的內容,而且在匹配’Raj’的行後面打印出來:

[root@ceph-node5 ~]# sed '/Raj/ r log.txt' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
log: input.txt
log:
log: testing resumed
log:
log:output created
104,Anand Ram,Developer
105,Jane Miller,Sales Manager

 

 

sed 模擬 Unix 命令(cat,grep,read)

 

 以前的例子的完成的功能都很像標準的 Unix 命令。使用 sed 能夠模擬不少 Unix 命令。完成它們,以便更好地理解 sed 的工做過程

 

模擬 cat 命令

 

cat employee.txt

 


下面的每一個 sed 命令的輸出都和上面的 cat 命令的輸出同樣:

sed 's/JUNK/&/p' employee.txt 
sed -n 'p' employee.txt
sed 'n' employee.txt
sed 'N' employee.txt

 

 

 

模擬 grep 命令



 

grep Jane employee.txt

 


下面的每一個 sed 命令的輸出都和上面的 grep 命令的輸出同樣:

sed -n 's/Jane/&/ p' employee.txt 
sed -n '/Jane/ p' employee.txt

 



grep –v (打印不匹配的行):

sed -n '/Jane/ !p' employee.txt 

 


注意: 這裏不能使用 sed –n 's/Jane/&/ !p' 了。



模擬 head 命令

 

head -10 /etc/passwd

 


下面的每一個 sed 命令的輸出都和上面的 head 命令的輸出同樣:

sed '11,$ d' /etc/passwd 
sed -n '1,10 p' /etc/passwd
sed '10 q' /etc/passwd

 

 

 

sed 命令選項



-n 選項

 


以前已經討論過屢次,而且在不少例子中也使用到了-n 選項。 該選項屏蔽 sed 的默認輸出。
也可使用—quiet,或者—silent 來代替-n,它們的做用是相同的。
下面全部命令都是等價的:

sed -n 'p' employee.txt 
sed --quiet 'p' employee.txt

 

 

-f 選項

 


能夠把多個 sed 命令保存在 sed 腳本文件中,而後使用-f 選項來調用,這點以前已經演示過
了。你也可使用--
file 來代替-f
下面的命令是等價的:

sed -n -f test-script.sed /etc/passwd  
sed -n -file=test-script.sed /etc/passwd

 

 

-e 選項

 


該選項執行來自命令行的一個
sed 命令,可使用多個-e 來執行多個命令。也可使用-expression 來代替。
下面全部命令都是等價的
:

sed -n -e '/root/ p' /etc/passwd  
sed -n --expression '/root/ p' /etc/passwd

 



-i 選項

下面全部命令都是等價的:
咱們已經提到, sed 不會修改輸入文件,只會把內容打印到標準輸出,或則使用 w 命令把內容寫到不一樣的文件中。 咱們也展現瞭如何使用-i 選項來直接修改輸入文件。
在原始文件
employee.txt 中,用 Johnny 替換 John:

sed -i 's/John/Johnny/' employee.txt 

 


執行和上面相同的命令,但在修改前備份原始文件:

sed -ibak 's/John/Johnny/' employee.txt 

 


也可使用--in-place 來代替-i:
下面的命令是等價的:

 sed -ibak 's/John/Johnny/' employee.txt
sed --in-place=bak 's/John/Johnny/' employee.txt

 



 

-c 選項

該選項應和-i 配合使用。使用-i 時,一般在命令執行完成後, sed 使用臨時文件來保持更改後的內容,而後把該臨時文件重命名爲輸入文件。

但這樣會改變文件的全部者(奇怪的是個人測試結果是它不會改變文件全部者),配合 c 選項,能夠保持文件全部者不變。也可使用--copy 來代替。
下面的命令是等價的
:

sed -ibak -c 's/John/Johnny/' employee.txt 
sed --in-place=bak --copy 's/John/Johnny/' employee.txt

 



-l 選項

 


指定行的長度,須要和
l 命令配合使用(注意選項 l 和命令 l,不要弄混了,上面提到的命令 i
和選項 i 也不要搞錯)使用-l 選項即指定行的長度。也可使用--line-length 來代替.
下面的命令是等價的:

sed -n -l 20 'l' employee.txt

 



請注意,下面的例子不使用-l(原文是-n,應該是弄錯)選項,一樣能夠獲取相同的輸出:

sed -n 'l 20' employee.txt --posix option  

 

 

打印模式空間(命令 n)

 


命令 n 打印當前模式空間的內容,而後從輸入文件中讀取下一行。 若是在命令執行過程當中遇到 n,那麼它會改變正常的執行流程。
打印每一行在模式空間中的內容:

sed n employee.txt

 


若是使用了-n 選項,將沒有任何輸出:

 sed -n n employee.txt

 


再次提醒:不要把選項-n 和命令 n 弄混了)
前面提到, sed 正常流程是讀取數據、執行命令、打印輸出、重複循環。
命令
n 能夠改變這個流程,它打印當前模式空間的內容,而後清除模式空間,讀取下一行進
來,而後繼續執行後面的命令。
假定命令
n 先後各有兩個其餘命令,以下:

sed-command-1
sed-command-2
n
sed-command-3
sed-command-4

 


這種狀況下, sed-command-1 sed-command-2 會在當前模式空間中執行,而後遇到 n,它打印當前模式空間的內容,並清空模式空間,讀取下一行,

而後把 sed-command-3 sed-command-4 應用於新的模式空間的內容。
提示:上面的例子中能夠看到,命令
n 自己沒有多大用處,然而當它和保持空間的命令配合使用時,就很強大了,後面會詳細解釋。

 

7、保持空間和模式空間命令

 

 

SED之因此能以行爲單位的編輯或修改文本,其緣由在於它使用了兩個空間:一個是活動的模式空間(pattern space),另外一個是起輔助做用的暫存緩衝區(holdingspace)這2個空間的使用。

模式空間:如你所知,模式空間用於 sed 執行的正常流程中。 該空間 sed 內置的一個緩衝區,用來存放、修改從輸入文件讀取的內容。

 保持空間: 保持空間是另一個緩衝區,用來存放臨時數據。 Sed 能夠在保持空間和模式空間交換數據,可是不能在保持空間上執行普通的 sed 命令。 咱們已經討論
過,每次循環讀取數據過程當中,模式空間的內容都會被清空,然而保持空間的內容則保持不變,不會在循環中被刪除。

 

sed編輯器逐行處理文件,並將輸出結果打印到屏幕上。sed命令將當前處理的行讀入模式空間(pattern space)進行處理,sed在該行上執行完全部命令後就將處理好的行打印到屏幕上(除非以前的命令刪除了該行),sed處理完一行就將其從模式空間中刪除,而後將下一行讀入模式空間,進行處理、顯示。處理完文件的最後一行,sed便結束運行。sed在臨時緩衝區(模式空間)對文件進行處理,因此不會修改原文件,除非顯示指明-i選項。

模式空間:能夠想成工程裏面的流水線,數據之間在它上面進行處理,用於處理文本行。

保持空間:能夠想象成倉庫,咱們在進行數據處理的時候,做爲數據的暫存區域,用於保留文本行,是保存已經處理過的輸入行,默認有一個空行。

 

與模式空間和暫存空間(hold space)相關的命令:

 

n 輸出模式空間行,讀取下一行替換當前模式空間的行,執行下一條處理命令而非第一條命令。

N 讀入下一行,追加到模式空間行後面,此時模式空間有兩行。

h 把模式空間的內容複製到保留空間,覆蓋模式

H 把模式空間的內容追加到保留空間,追加模式

g 把保留空間的內容複製到模式空間,覆蓋模式

G 把保留空間的內容追加到模式空間,追加模式

x 將暫存空間的內容於模式空間裏的當前行互換。

! 對所選行之外的全部行應用命令。

注意:暫存空間裏默認存儲一個空行。



 

 

 

 

請先創建以下文件,以用於保持空間的示例:

[root@ceph-node5 ~]# vim empnametitle.txt
John
Doe
CEO
Jason Smith
IT Manager
Raj Reddy
Sysadmin
Anand Ram
Developer
Jane Miller
Sales Manager


能夠看到,在這個文件中,每一個僱員的名稱和職位位於連續的兩行內。

 

用保持空間替換模式空間(命令 x)

 

命令 x(Exchange)交換模式空間和保持空間的內容。 該命令自己沒有多大用處,但若是和其餘命令配合使用,則很是強大了。
假定目前模式空間內容爲"
line 1",保持空間內容爲"line 2"。那麼執行命令 x 後,模式空間的內容變爲」line 2」,保持空間的內容變爲"line 1"

 

 

把模式空間的內容複製到保持空間(命令 h)

 


命令 h(hold)把模式空間的內容複製到保持空間,和命令 x 不一樣,命令 h 不會修改當前模式空間的內容。 執行命令 h 時,當前保持空間的內容會被模式空間的內容覆蓋。假定目前模式空間內容爲"line 1",保持空間內容爲"line 2"。那麼執行命令 h 後,模式空間的內容仍然爲"line 1",保持空間的內容則變爲"line 1"
打印管理者的名稱
:

[root@ceph-node5 ~]# sed -n -e '/Manager/!h' -e '/Manager/{x;p}' empnametitle.txt
Jason Smith
Jane Miller

 

上面例子中:

/Manager/!h –若是模式空間內容不包含關鍵字’Manager’(模式後面的!表示不匹配該模式), 那麼複製模式空間內容到保持空間。 (這樣一來,保持空間的內容可能會
是僱員名稱或職位,而不是’Manager’.)注意, 和前面的例子不一樣,這個例子中沒有使用命令 n 來獲取下一行,而是經過正常的流程來讀取後續內容。


/Manager/{x;p} –若是模式空間內容包含關鍵字’Manager’,那麼交換保持空間和模式空間的內容,並打印模式空間的內容。 這和咱們在命令 x 的示例中的用法是相同的

 

你也能夠把上面命令保存到 sed 腳本中執行:

[root@ceph-node5 ~]# vi h.sed
#!/bin/sed -nf
/Manager/!h
/Manager/{x;p}

[root@ceph-node5 ~]#  chmod u+x h.sed
[root@ceph-node5 ~]# ./h.sed empnametitle.txt
Jason Smith
Jane Miller

 

 

把模式空間內容追加到保持空間(命令 H)

大寫 H 命令表示把模式空間的內容追加到保持空間,追加以前保持空間的內容不會被覆蓋;
相反, 它在當前保持空間內容後面加上換行符
\n,而後把模式空間內容追加進來。
假定目前模式空間內容爲
」line 1」,保持空間內容爲」line 2」。那麼執行命令 H 後,模式空間的內容沒有改變, 仍然爲」line 1」,保持空間的內容則變爲」line2\nline 1」
打印管理者的名稱和職位
(在不一樣的行上):

[root@ceph-node5 ~]# sed -n -e '/Manager/!h' -e '/Manager/{H;x;p}' empnametitle.txt
Jason Smith
IT Manager
Jane Miller
Sales Manager

 


上面例子中:

/Manager/!h –若是模式空間內容不包含關鍵字’Manager’(模式後面的!表示不匹配該模式),那麼複製模式空間內容到保持空間。 (這樣一來,保持空間的內容可能會
是僱員名稱或職位,而不是’Manager’.)。這和以前使用命令 h 的方法是同樣的。


/Manager/{H;x;p} –若是模式空間內容包含關鍵字’Manager’,那麼命令 H 把模式空間的內容(也就是管理者的職位)做爲新行追加到保持空間,因此保持空間內容會變 爲」僱員名稱\n 職位」(職位包含關鍵字 Manager)。 而後命令 x 交換模式空間和保持空間的內容,隨後命令 p 打印模式空間的內容。

 

你也能夠把上面命令保存到 sed 腳本中執行:

[root@ceph-node5 ~]# vi H-upper.sed 
#!/bin/sed -nf
/Manager/!h
/Manager/{H;x;p}
[root@ceph-node5 ~]# chmod u+x H-upper.sed
[root@ceph-node5 ~]# ./H-upper.sed empnametitle.txt
Jason Smith
IT Manager
Jane Miller
Sales Manager

 


若是想把僱員名稱和職位顯示在同一行,以分號分開,那麼只需稍微修改一下便可,以下:

[root@ceph-node5 ~]#  sed -n -e '/Manager/!h' -e '/Manager/{H;x;;s/\n/:/p}' empnametitle.txt
Jason Smith:IT Manager
Jane Miller:Sales Manager

 


這個例子除了在第二個-e 後面的命令中加入了替換命令以外,和前面的例子同樣。 Hx p 都完成和以前相同的操做;在交換模式空間和保持空間以後,命令 s 把換行符\n 替換爲分號,而後打印出來。
你也能夠把上面命令保存到
sed 腳本中執行:

[root@ceph-node5 ~]# vi H1-upper.sed
#!/bin/sed -nf
/Manager/!h
/Manager/{H;x;s/\n/:/;p}
[root@ceph-node5 ~]# chmod u+x H1-upper.sed
[root@ceph-node5 ~]# ./H1-upper.sed empnametitle.txt
Jason Smith:IT Manager
Jane Miller:Sales Manager

 

 

 

把保持空間內容複製到模式空間(命令 g)

 

命令 g(get)把保持空間的內容複製到模式空間。
這樣理解:命令 h 保持(hold)住保持空間(hold space),命令 g 從保持空間獲取(get)內容。
假定當前模式空間內容爲」line 1」,保持空間內容爲」line 2」;執行命令 g 以後,模式空間內容變爲」line 2」,保持空間內容仍然爲」line 2」

打印管理者的名稱:

[root@ceph-node5 ~]# sed -n -e '/Manager/!h' -e '/Manager/{g;p}' empnametitle.txt
Jason Smith
Jane Miller

 




上面例子中:

/Manager/!h –最近幾個例子都在用它。若是模式空間內容不包含關鍵字’Manager’,那麼就把他複製到保持空間。
/Manager/{g;p} –把保持空間的內容丟到模式空間中,而後打印出來

 

你也能夠把上面命令保存到 sed 腳本中執行:

[root@ceph-node5 ~]# vi g.sed
#!/bin/sed -nf
/Manager/!h
/Manager/{g;p}
[root@ceph-node5 ~]# chmod u+x g.sed
[root@ceph-node5 ~]# ./g.sed empnametitle.txt
Jason Smith
Jane Miller

 

把保持空間追加到模式空間(命令 G)


大寫 G 命令把當前保持空間的內容做爲新行追加到模式空間中。模式空間的內容不會被覆蓋,該命令在模式空間後面加上換行符\n,而後把保持空間內容追加進去。
G g 的用法相似於 H h;小寫命令替換原來的內容,大寫命令追加原來的內容。
假定當前模式空間內容爲
」line 1」,保持空間內容爲」line 2」;命令 G 執行後,模式空間內容變爲」line 1\nline 2」,同時保持空間內容不變,仍然爲」line 2」
以分號分隔,打印管理者的名稱和職位
:

[root@ceph-node5 ~]# sed -n -e '/Manager/!h' -e '/Manager/{x;G;s/\n/:/;p}' empnametitle.txt
Jason Smith:IT Manager
Jane Miller:Sales Manager


上面例子中:

 

/Manager/!h –和前面的例子同樣,若是模式空間內容不包含關鍵字’Manager’,那麼就把他複製到保持空間。
/Manager/{x;G;s/\n/:/;p} –若是模式空間包含’Manager’,那麼:
  x –交換模式空間和保持空間的內容。
  G –把保持空間的內容追加到模式空間。
  s/\n/:/ --在模式空間中,把換行符替換爲分號:。
  p 打印模式空間內容
  注意: 若是捨去命令 x,即便用/Manager/{G;s/\n/:/;p},那麼結果會由「僱員職位: 僱員名稱」變成」僱員名稱: 僱員職位

 

也可把上述命令寫到 sed 腳本中而後執行:

[root@ceph-node5 ~]# vi G-upper.sed
#!/bin/sed -nf
/Manager/!h
/Manager/{x;G;s/\n/:/;p}
[root@ceph-node5 ~]# ./G-upper.sed empnametitle.txt
Jason Smith:IT Manager
Jane Miller:Sales Manager

 

 

8、sed 多行模式及循環

 
 Sed 默認每次只處理一行數據,除非使用 H,G 或者 N 等命令建立多行模式,每行之間用換行符分開。
本章將解釋適用於多行模式的
sed 命令。
提示:在處理多行模式是,請務必牢記
^只匹配該模式的開頭,即最開始一行的開頭,且$只匹配該模式的結尾,即最後一行的結尾。

讀取下一行數據並附加到模式空間(命令 N)

就像大寫的命令 H G 同樣,只會追加內容而不是替換內容,命令 N 從輸入文件中讀取下一行並追加到模式空間,而不是替換模式空間。
前面提到過,小寫命令
n 打印當前模式空間的內容, 並清空模式空間,從輸入文件中讀取下一行到模式空間,而後繼續執行後面的命令。
大寫命令
N,不會打印模式空間內容,也不會清除模式空間內容,而是在當前模式空間內容後加上換行符\n,而且從輸入文件中讀取下一行數據,

追加到模式空間中,而後繼續執行後面的命令。
以分號分隔,打印僱員名稱和職位
:

[root@ceph-node5 ~]# sed -e '{N;s/\n/:/}' empnametitle.txt
John:Doe
CEO:Jason Smith
IT Manager:Raj Reddy
Sysadmin:Anand Ram
Developer:Jane Miller
Sales Manager

 



這個例子中:

N 追加換行符\n 到當前模式空間(僱員名稱)的最後,而後從輸入文件讀取下一行數據,追加進來。所以,當前模式空間內容變爲」僱員名稱\n 僱員職位」。
s/\n/:/ 把換行符\n 替換爲分號,把分號做爲僱員名稱和僱員職位的分隔符

流程以下圖所示:

 

 

 

 

 

打印多行模式中的第一行(命令 P)

目前爲止,咱們已經學會了三個大寫的命令(H,N,G),每一個命令都是追加內容而不是替換內容。
如今咱們來看看大寫的
D P,雖然他們的功能和小寫的 d p 很是類似,但他們在多行模式中有特殊的功能。
以前說到,小寫的命令
p 打印模式空間的內容。大寫的 P 也打印模式空間內容,直到它遇到換行符\n

 

 

下面的例子將打印全部管理者的名稱:

( cat << EOF
John
Doe
CEO
Jason Smith
IT Manager
Raj Reddy
Sysadmin
Anand Ram
Developer
Jane Miller
Sales Manager
EOF
) > empname.txt
[root@ceph-node5 ~]# sed -n -e '/Manager/!h' -e'/Manager/{x;p}' empname.txt
Jason Smith
Jane Miller

 

 

 

 

 

 

刪除多行模式中的第一行(命令 D)

以前提到,小寫命令 d 會刪除模式空間內容,而後讀取下一條記錄到模式空間,並忽略後面的命令,從頭開始下一次循環。
大寫命令
D,既不會讀取下一條記錄,也不會徹底清空模式空間(除非模式空間內只有一行)
它只會:

刪除模式空間的部份內容,直到遇到換行符\n
忽略後續命令,在當前模式空間中從頭開始執行命令

 

 

 

假設有下面文件,每一個僱員的職位都用@包含起來做爲註釋。 須要注意的是,有些註釋是跨
行的。 如
@Information Technology officer@就跨了兩行。請先創建下面示例文件:

[root@ceph-node5 ~]# vim empnametitle-with-commnet.txt
John Doe
CEO @Chief Executive Officer@
Jason Smith
IT Manager @Infromation Technology
Officer@
Raj Reddy
Sysadmin @System Administrator@
Anand Ram
Developer @Senior
Programmer@
Jane Miller
Sales Manager @Sales
Manager@

 


如今咱們的目標是,去掉文件裏的註釋:

[root@ceph-node5 ~]#  sed -e '/@/{N;/@.*@/{s/@.*@//;P;D}}' empnametitle-with-commnet.txt
John Doe
CEO 
Jason Smith
IT Manager 
Raj Reddy
Sysadmin 
Anand Ram
Developer 
Jane Miller
Sales Manager 

 

也可把上述命令寫到 sed 腳本中而後執行:

[root@ceph-node5 ~]# vim D-upper.sed
#!/bin/sed -f
/@/{
N
/@.*@/{s/@.*@//;P;D}
}
[root@ceph-node5 ~]# ./D-upper.sed empnametitle-with-commnet.txt
John Doe
CEO
Jason Smith
IT Manager
Raj Reddy
Sysadmin
Anand Ram
Developer
Jane Miller
Sales Manager

 


這個例子中:

 

/@/{ 這是外傳循環。 Sed 搜索包含@符號的任意行,若是找到,就執行後面的命令;若是沒有找到,則讀取下一行。 爲了便於說明,以第 4 行,即」@Information
Technology」(這條註釋跨了兩行)爲例,它包含一個@符合,因此後面的命令會被執行。
N 從輸入文件讀取下一行,並追加到模式空間,以上面提到的那行數據爲例,這裏 N 會讀取第 5 行,即」Officer@」並追加到模式空間,所以模式空間內容變
爲」@Informatioin Technology\nOfficer@」。
/@.*@/ 在模式空間中搜索匹配/@.*@/的模式,即以@開頭和結尾的任何內容。當前模式空間的內容匹配這個模式,所以將繼續執行後面的命令。
s/@.*@//;P;D 這個替換命令把整個@Information Technology\nOfficer@」替換爲空(至關於刪除)。 P 打印模式空間中的第一行,而後 D 刪除模式空間中的第一行,然
後從頭開始執行命令(即不讀取下一條記錄,又返回到/@/處執行命令)

 

循環和分支(命令 b :label 標籤)

使用標籤和分支命令 b,能夠改變 sed 的執行流程:

:label 定義一個標籤
b lable 執行該標籤後面的命令。 Sed 會跳轉到該標籤,而後執行後面的命令。
注意:命令 b 後面能夠不跟任何標籤,這種狀況下,它會直接跳到 sed 腳本的結尾

下面例子將把 empnametitle.txt 文件中的僱員名稱和職位合併到一行內,字段之間以分號:
分隔,而且在管理者的名稱前面加上一個星號
*

[root@ceph-node5 ~]# vim label.sed
#!/bin/sed -nf
h;n;H;x
s/\n/:/
/Manager/!b end
s/^/*/
:end
p

 


這個腳本中,鑑於以前的例子,你已經知道 h;n;H;x s/\n/:/的做用了。下面是關於分支的操做

Manager/!b end 若是行內不包含關鍵字」Manager」,則 跳轉到’end’標籤,請注意,
你能夠任意設置你想要的標籤名稱。 所以,只有匹配 Manager 的僱員名稱簽名,纔會執行 s/^/*/(在行首加上星號*)。
:end 便是標籤

 

給這個腳本加上可執行權限,而後執行:

$ chmod u+x label.sed
$ ./label.sed empnametitle.txt
John Doe:CEO
*Jason Smith:IT Manager
Raj Reddy:Sysadmin
Anand Ram:Developer
*Jane Miller:Sales Manager

 


我的以爲腳本里面的 h;n;H;x 能夠用一個 N 替代, 這樣就不用使用保持空間了。
若是不使用標籤,還能夠: sed 'N;s/\n/:/;/Manager/s/^/\.*/' empnametitle.txt

 

注意:我這裏顯示的結果:

[root@ceph-node5 ~]#  chmod u+x label.sed
[root@ceph-node5 ~]# ./label.sed empnametitle.txt
John:Doe
CEO:Jason Smith
*IT Manager:Raj Reddy
Sysadmin:Anand Ram
Developer:Jane Miller

 

 

使用命令 t 進行循環


命令 t 的做用是,若是前面的命令執行成功,那麼就跳轉到 t 指定的標籤處,繼續往下執行後續命令。 不然,仍然繼續正常的執行流程。
下面例子將把 empnametitle.txt 文件中的僱員名稱和職位合併到一行內,字段之間以分號:分隔,而且在管理者的名稱前面加上三個星號*
提示:咱們只需把前面例子中的替換命令改成 s/^/***/便可帶到該目的,下面這個例子僅僅是爲了解釋命令 t 是如何運行的。

$ vi lable-t.sed
#!/bin/sed -nf
h;n;H;x
s/\n/:/
: repeat
/Manager/s/^/*/
/\*\*\*/! t repeat
p
$ chmod u+x lable-t.sed
$ ./lable-t.sed empnametitle.txt
John Doe:CEO
***Jason Smith:IT Manager
Raj Reddy:Sysadmin
Anand Ram:Developer
***Jane Miller:Sales Manager
這個例子中:

 

這個例子中:

下面的代碼執行循環
:repeat
/Manager/s/^/*/
/\*\*\*/! t repeat
/Manager/s/^/*/ 若是匹配到 Manager,在行首加上星號*
/\*\*\*/!t repeat 若是沒有匹配到三個連續的星號*(用/\*\*\*/!來表示),而且前面
一行的替換命令成功執行了,則跳轉到名爲 repeat 的標籤處(即 t repeat)
:repeat 標籤

 

 

 

九·、綜合案例(案例摘自 GNU sed 官網)

綜合案例 1:重命名文件名爲小寫

[jacob@localhost ~] #cat   sed.sh
#! /bin/sh
# rename files to lower/upper case...
#
# usage:
#       move-to-lower *
#       move-to-upper *
# or
#       move-to-lower -R .
#       move-to-upper -R .
#
help()
{
cat << eof
Usage: $0 [-n] [-r] [-h] files...
-n           do nothing, only see what would be done
-R           recursive (use find)
-h           this message
files     files to remap to lower case
Examples:
$0 -n *               (see if everything is ok, then...)
$0 *
$0 -R .
eof
}
apply_cmd='sh'
finder='echo "$@" | tr " " "\n"'
files_only=
while :
do
case "$1" in
-n) apply_cmd='cat' ;;
-R) finder='find "$@" -type f';;
-h) help ; exit 1 ;;
*) break ;;
esac
shift
done
if [ -z "$1" ]; then
echo Usage: $0 [-h] [-n] [-r] files...
exit 1
fi
LOWER='abcdefghijklmnopqrstuvwxyz'
UPPER='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
case `basename $0` in
*upper*) TO=$UPPER; FROM=$LOWER ;;
*)             FROM=$UPPER; TO=$LOWER ;;
esac
eval $finder | sed -n '
# remove all trailing slashes
s/\/*$//
# add ./ if there is no path, only a filename
/\//! s/^/.\//
# save path+filename
h
# remove path
s/.*\///
# do conversion only on filename
y/'$FROM'/'$TO'/
# now line contains original path+file, while
# hold space contains the new filename
x
# add converted file name to line, which now contains
# path/file-name\nconverted-file-name
G
# check if converted file name is equal to original file name,
# if it is, do not print nothing
/^.*\/\(.*\)\n\1/b
# now, transform path/fromfile\n, into
# mv path/fromfile path/tofile and print it
s/^\(.*\/\)\(.*\)\n\(.*\)$/mv "\1\2" "\1\3"/p
' | $apply_cmd
綜合案例 2:獲取 bash 環境變量
#!/bin/sh
set | sed -n '
:x
# if no occurrence of ‘=()’ print and load next line
/=()/! { p; b; }
/ () $/! { p; b; }
# possible start of functions section
# save the line in case this is a var like FOO="() "
h
# if the next line has a brace, we quit because
# nothing comes after functions
n
/^{/ q
# print the old line
x; p
# work on the new line now
x; bx

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 sed文件塊處理

 

文件塊處理動做

 

操做符    用途            指令示例
i      行前插入文本    2iYY 在第2行以前添加文本行」YY」
                 4,7iYY 在第4-7行的每一行前添加文本行
a    行後插入文本       2aYY 在第2行以後添加文本
                 /^XX/aYY 在以XX開頭的行以後添加文本
c    替換當前行      2cYY 將第2行的內容修改成」YY」

 

sed逐字符替換

操做y操做可實現逐個字符替換

 

 

修改後的文本有多行時

 

 

以換行符\n分隔
或者,以\強制換行

 

 

 

 

 sed行替換的應用

 

 

 

 sed行替換的應用:

找到主機名配置中的HOSTNAME行

整行替換爲新的主機名配置

 

 

 

 

 

 

 

 

 

[root@localhost shell]# grep ^HOSTNAME /etc/sysconfig/network
HOSTNAME=localhost.localdomain              //修改前
[root@localhost shell]# sed -i '/HOSTNAME/cHOSTNAME=mysvr.tarena.com' /etc/sysconfig/network         //整行替換操做
[root@localhost shell]# grep ^HOSTNAME                         /etc/sysconfig/networkHOSTNAME=mysvr.tarena.com         //修改後

 

 

 

 

 

 

 

 

sed導入導出

 

 

導入導出動做

 

r動做應結合-i選項纔會存入,不然只輸出
w 動做以覆蓋的方式另存爲新文件

 

例子:

操做符      用途        指令示例
r      讀入其餘文件      3r b.txt 在第3行下方插入文件b.txt
                   4,7r b.txt 在第4-7每一行後插入文件b.txt
w      寫入其餘文件      3w c.txt 將第3行另存爲文件c.txt
                   4,7w c.txt 將第4-7行另存爲文件c.txt

 

sed複製剪切

 

模式空間

 

存放當前處理的行,將處理結果輸出
若當前行不符合處理條件,則原樣輸出
處理完當前行再讀入下一行來處理

 

 保持空間

 

 

做用相似於'剪切板'
默認存放一個空行(換行符\n)

 

主要處理動做

 

複製到剪貼板:

 


H    模式空間 ---[追加]--->保持空間
h    模式空間 ---[覆蓋]--->保持空間

 

 

 

讀取剪貼板內容並粘貼:

 

G    保持空間 ---[追加]--->模式空間
g    保持空間 ---[覆蓋]--->模式空間

 

 

 

 

 

 

 

 sed 的工做過程:

 

把要處理的行先讀入本身模式空間,而後用處理動做處理,處理完後輸出處理後的結果,並把源數據輸出,而後讀入下一行到模式空間進行處理
* 要處理的數據必須在模式空間,且模式空間不存儲數據
保持空間 保持空間裏默認只保存一個換行符號\n
要想存數據放到保持空間裏,要手動把數據存進來了才能夠;
 保持空間只負責存儲數據,不會輸出數據
要想保持空間裏的數據被sed處理,必須手動把保存空間裏的數據調入模式空間
* 保持空間只負責存儲數據 放在保持空間裏的數據不會被輸出也不會被處理。保持空間裏默認只保存一個換行符號\n

 

 

sed流控制 

 

參數選項      註釋
!取反操做    根據定址條件取反
n讀下一行    讀入下一行進行處理(產生隔行的效果)

 

 

 

 

 

 

 

 

 

sed練習:

1、刪除/etc/grub.conf文件中行首的空白符;
sed -r 's@^[[:spapce:]]+@@g' /etc/grub.conf
2、替換/etc/inittab文件中"id:3:initdefault:"一行中的數字爲5;
sed 's@\(id:\)[0-9]\(:initdefault:\)@\15\2@g' /etc/inittab
3、刪除/etc/inittab文件中的空白行;
sed '/^$/d' /etc/inittab
4、刪除/etc/inittab文件中開頭的#號;
sed 's@^#@@g' /etc/inittab
5、刪除某文件中開頭的#號及後面的空白字符,但要求#號後面必須有空白字符;
sed -r 's@^#[[:space:]]+@@g' /etc/inittab
6、刪除某文件中以空白字符後面跟#類的行中的開頭的空白字符及#
sed -r 's@^[[:space:]]+#@@g' /etc/inittab
7、取出一個文件路徑的目錄名稱;
echo "/etc/rc.d/" | sed -r 's@^(/.*/)[^/]+/?@\1@g'    
基名:
echo "/etc/rc.d/" | sed -r 's@^/.*/([^/]+)/?@\1@g'    
相關文章
相關標籤/搜索