之前介紹了三大文本編輯器的grep,這裡介紹比grep功能更強的sed流編輯器
Linux文本處理工具grep和正則表達式及egrep與grep區別 http://www.linuxidc.com/Linux/2016-08/134046.htm
sed是什麼?
sed是Stream EDitor的縮寫,man中對sed的簡介為
sed - stream editor for filtering and transforming text
它的主要功能是對文本的過濾與替換。
sed的工作原理
sed的工作過程:sed是一個流編輯器,所謂流編輯器是指sed每次只從文件或stdin中讀入一行,將讀入的行保存至模式空間然後根據指定的要求對其進行處理,並將處理後的結果輸出至屏幕,接著讀入下一行,整個文本的過程如流水線般被逐行處理後輸出。
sed對內容的處理方式:sed不是在原文件中或原輸入上直接進行處理的,它將讀入的行放入緩存區,對緩存區裡的內容進行處理,處理完畢後默認不會寫入或覆蓋源文件,而是直接輸出到屏幕上。
它有兩個內存緩沖區分別叫做:模式空間(pattern space)、保持空間也有稱作暫存緩存區(holding space)。
一般情況下sed首先把第一行裝入模式空間,進行處理後輸出屏幕,然後第二行裝入模式空間替換掉模式空間裡原來的內容,再進行處理,依次循環,直至結束。
下面是我對sed工作流程的理解圖。
1、sed每次將stdin中的內容中的一行讀入模式空間
2、之後根據模式空間中的匹配條件進行匹配,符合條件進入下一階段即普通編輯,不滿足則默認至標准輸出,結束
3、普通編輯之後分三個階段,1)普通編輯之後選擇性顯示至STDOUT,結束;2)進入holding space進行高級編輯,編輯結束後選擇性顯示至模式空間,之後再次根據編輯命令重復2-3過程;3)若是出現多編輯命令則需要再返回模式空間根據編輯條件再次進行2-3步驟。
限於個人理解程度上述的理解免不了跟真實的工作流程有些出入,大家要抱著質疑的態度去看,我寫的不一定都是對的,不過錯的應該不至於很多。
sed語法
sed OPTIONS... <SCRIPT> [INPUTFILE...]
[SCRIPT]:可以理解為地址定界加編輯命令。
常用選項:
-n:不輸出模式空間中的內容至屏幕;通俗點可以理解為它可以自動過濾掉模式空間中未匹配到的行,-n 要與命令編輯中的p合用(命令編輯見下文),用於顯示模式空間中被匹配到的內容。
suppress automatic printing of pattern space
-n的具體應用見後面的sed編輯高級命令演示
-e:多點編輯
add the script to the commands to be executed
-f:每行一個編輯命令
add the contents of script-file to the commands to be executed
-r:使用擴展表達式
use extended regular expressions in the script.
-i:直接編輯原文件
edit files in place (makes backup if SUFFIX supplied)
SCRIPT:
之前對這塊很迷糊,因為info中sed顯示語法有[]表示可加可不加,於是就在sed後直接加想要編輯的文本
於是就出現如下情況
1 2[root@localhost
test
]
# sed sed1
sed
:-e 表達式
#1,字符 4:未終止的“s”命令
報錯信息沒找到終止的限制條件,所以上面的sed語法格式並不准確。
通過實驗,sed可以不加[OPTION]但是[SCRIPT]則必須添加
SCRIPT分兩部分:地址定界(用於限定編輯文本的范圍)、編輯命令(用於對匹配到的內容進行什麼樣的操作或編輯),前者可少後者必不可少,如果沒有編輯的命令會發生如下錯誤
[root@localhost
test
]
# sed '1' cat1
sed
:-e 表達式
#1,字符 1:遺漏命令
[root@localhost
test
]
# cat cat1
hi,everyone
now I will show how to use
cat
[root@localhost
test
]
# sed 'p' cat1
hi,everyone
hi,everyone
now I will show how to use
cat
now I will show how to use
cat
地址定界:
1、空地址:對全文處理。
2、單地址:
#:指定行;
/pattern/:被此模式所匹配到的每一行;
3、地址范圍:
#,#:從#開始到#結束的所有行
#,+#:從#開始向下至+#的行之間的所有行
#,/pat1/ 從#開始至匹配到第一次出現/pat1/模式的行之間的所有行
/pat1/,/pat2/:第一次匹配到/pat1/的行到第一次匹配到/pat2/的行之間的所有行
4、步進:~
1~2:所有奇數行 2~2:所有偶數行
編輯命令:若少了編輯命令會報錯,編輯命令在SCRIPT中至少出現一次。
d:刪除模式空間中匹配到的內容 Delete pattern space
a \text 在行後面插入文本“text”,支持使用\n實現多行插入
Append text, which has each embedded newline preceded by a back slash.
i \text 在行前面插入文本“text”,支持使用\n實現多行插入
Insert text, which has each embedded newline preceded by a back slash.
c \text 把匹配到的行替換為此處指定的文本“text”
Replace the selected lines with text, which has each embedded new line preceded by a backslash.
w filename 保存模式空間匹配的行至指定的文件中
Write the current pattern space to filename.
r filename 讀取指定文件內容至當前文件被模式匹配到的行文件後合並
Append text read from filename.
= : 為模式匹配到的行打印行號 Print the current line number.
!: 條件取反(它比較特殊,它必須跟其他編輯命令一起使用)
s/regexp/replacement/ : 查找替換,其分隔符可自行指定,常用有s@@@,s###
它有一個特殊的用法s//x&/:表示將被查找的內容在其前面添加x內容
s//&x/:表示將被查找的內容在其後面添加x內容
&代表被查找的內容
1 2 3 4 5 6 7 8 9[root@localhost
test
]
# cat cat1
hi,everyone
now I will show how to use
cat
[root@localhost
test
]
# sed 's/e/&#/' cat1
hi,e
#veryone
now I will show how to use
# cat
[root@localhost
test
]
# sed 's/e/#&/' cat1
hi,
#everyone
now I will show how to us
#e cat
p :顯示替換成功的行
g :全局替換
w filename : 將替換成功的結果保存至指定文件中
查找替換在sed中應用很廣,下面很多例子都是以sed的替換功能實現的
p :顯示當前模式空間中的內容 Print the current pattern space.
注:同時使用多個編輯命令,命令之間要用;隔開(!除外)
例子如下:
1 2 3 4 5 6 7[root@localhost
test
]
# sed 'p;=' cat1
hi,everyone
1
hi,everyone
now I will show how to use
cat
2
now I will show how to use
cat
實例演示:
1、刪除/etc/grub2.conf文件中所有以空白開頭的行行首的空白字符
1sed
's#^[[:space:]]\+##'
/etc/grub2
.cfg
這裡##是將前面匹配到的內容刪除的意思,上面文本內容太多,就不截取了。
2、刪除/etc/fstab文件中所有以#開頭,後面至少跟一個空白字符的行的行首的#號及#後面的所有空白字符
1sed
's@^#[[:space:]]\+@@'
/etc/fstab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost test]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Tue Jul 19 23:52:41 2016
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/CentOS-root / xfs defaults 0 0
UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
[root@localhost test]# sed
's@^#[[:space:]]\+@@'
/etc/fstab
#
/etc/fstab
Created by anaconda on Tue Jul 19 23:52:41 2016
#
Accessible filesystems, by reference, are maintained under
'/dev/disk'
See man pages fstab(5), findfs(8), mount(8) and/or blkid(8)
for
more info
#
/dev/mapper/centos-root / xfs defaults 0 0
UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
3、在/etc/fstab每一行行首增加#號
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Tue Jul
19
23
:
52
:
41
2016
#
# Accessible filesystems, by reference, are maintained under
'/dev/disk'
# See man pages fstab(
5
), findfs(
8
), mount(
8
) and/or blkid(
8
)
for
more info
#
/dev/mapper/centos-root / xfs defaults
0
0
UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot xfs defaults
0
0
/dev/mapper/centos-swap swap swap defaults
0
0
sed
's@^@#&@'
/etc/fstab
#
##
## /etc/fstab
## Created by anaconda on Tue Jul
19
23
:
52
:
41
2016
##
## Accessible filesystems, by reference, are maintained under
'/dev/disk'
## See man pages fstab(
5
), findfs(
8
), mount(
8
) and/or blkid(
8
)
for
more info
##
#/dev/mapper/centos-root / xfs defaults
0
0
#UUID=6efb8a23-bae1-427c-ab10-3caca95250b1 /boot xfs defaults
0
0
#/dev/mapper/centos-swap swap swap defaults
0
0
4、處理/etc/fstab路徑,使用sed命令取出其目錄名和基名
目錄名:
1 2[root@localhost
test
]
# echo '/etc/fstab' | sed -r 's#(.*/)([^/]+/?)#\1#'
/etc/
基名:
1 2[root@localhost
test
]
# echo '/etc/fstab' | sed -r 's#(.*/)([^/]+/?)#\2#'
fstab
sed高級編輯命令:
h:把模式空間中的內容覆蓋至保持空間中;
H:把模式空間中的內容追加至保持空間中;
g:把保持空間中的內容覆蓋至模式空間中;
G:把保持空間中的內容追加至模式空間中;
x:把模式空間中的內容與保持空間中的內容互換;
n:覆蓋讀取匹配到的行的下一行至模式空間中;
N:追加讀取匹配到的行的下一行至模式空間中;
d:刪除模式空間中的行;
D:刪除多行模式空間中的所有行;
我知道看了上面這些高級命令一定很暈,下面通過5個例子來理一下使用sed高級編輯命令的思路
高級編輯命令實例演示:
1、 sed -n 'n;p' FILE:
''內意思:將讀取到的行的下一行內容顯示至模式空間
-n 'p':將模式空間中被匹配到的內容顯示至屏幕
二者結合起來就是只顯示偶數行。
1 2 3 4 5[root@localhost
test
]
# cat -n cat1
1 hi,everyone
2 now I will show how to use
cat
[root@localhost
test
]
# sed -n 'n;p' cat1
now I will show how to use
cat
2、 sed '1!G;h;$!d' FILE:
這個命令按'x;x;x'中的;號分割分為三部分:
1、1!G:除讀取的第一行都進行G編輯
2、h:將模式空間中的內容覆蓋至保持空間中
3、$!d:刪除非最後一行的內容
命令解釋完了,我想大家對此應該還是一頭霧水,那麼就具體說明這個命令的意思:
1)讀取文本信息的1行內容至模式空間,由於是第一行所以模式空間中的1行不進行G操作,之後觸發h,將模式空間中的1行放入保持空間中,再之後觸發$!d,由於1行不是最後一行,所以將模式空間中的1行刪除;
2)讀取2行內容至模式空間,由於不是1行所以觸發G操作,將保持空間中1行追加到2行後面,此時模式空間中的順序內容為2行,1行,之後h命令將模式空間中內容覆蓋至保持空間中,此時保持空間內容為2行,1行,因為2行不是最後一行,所以$!d刪除模式空間中內容;
3)上述過程不斷重復,直到最後一行時不進行d操作,此時模式空間中的第一行就是原文件的最後一行。
因此這個命令就是原文件內容反過來的排列。
1 2 3 4 5 6[root@localhost
test
]
# cat cat1
hi,everyone
now I will show how to use
cat
[root@localhost
test
]
# sed '1!G;h;$!d' cat1
now I will show how to use
cat
hi,everyone
3、 sed '$!d' FILE:
經過了上面兩個命令的磨練,這個就顯得簡單了。
'$!d':不是最後一行則刪除
意思是說模式空間中只保留文本的最後一行
1 2[root@localhost
test
]
# sed '$!d' cat1
now I will show how to use
cat
4、 sed '/^$/d;G' FILE
'/^$/d':查找模式空間中的每行是否包含空白行,若包含則將其刪除
G:將保持空間中的內容追加至模式空間中的每行後面
刪除原有的所有空白行,而後為所有的非空白行後添加一個空白行;
二者結合在一起即:保證指定文件每一行後方有且只有一個空白行
1 2 3 4[root@localhost
test
]
# sed '/^$/d;G' cat1
hi,everyone
now I will show how to use
cat
5、 sed 'n;d' FILE:顯示奇數行;
這個就很簡單了,大家按照sed的工作原理及編輯命令n與d很容易就能明白其所表達的意思
1 2 3 4 5[root@localhost
test
]
# cat cat1
hi,everyone
now I will show how to use
cat
[root@localhost
test
]
# sed 'n;d' cat1
hi,everyone
學習sed的一些感受
學習sed如果對於sed的編輯命令或高級命令很困惑,那麼不妨試試照著我上面的sed工作流程圖,一步一步的自己畫圖分析每一步所代表的意思。這既能加強自己對sed這個工具的了解也可有助於理清我們的使用思路。這是我在學習過程中覺得很有用的一種方法。
sed這個工具它的精髓在於它的替換,替換的精髓在於精確匹配,而精確匹配又離不開正則表達式的,所以如果覺得自己對於替換很不擅長的話那麼可以好好練習一下正則表達式。
sed是一個實用性很強的文本編輯工具,由於能力所限,也只能對sed進行下簡要的介紹,大家若對其有進一步的興趣可以查找更專業的書籍。
在sed命令中引入shell變量 http://www.linuxidc.com/Linux/2014-03/97896.htm
Linux下Shell編程——sed命令基本用法 http://www.linuxidc.com/Linux/2013-06/85526.htm
Unix文本處理工具之sed http://www.linuxidc.com/Linux/2013-08/89315.htm
sed 高級用法 http://www.linuxidc.com/Linux/2014-09/106961.htm
sed命令詳解與示例 http://www.linuxidc.com/Linux/2014-11/109325.htm
Linux正則表達式sed 詳述 http://www.linuxidc.com/Linux/2015-04/116309.htm
Linux文本處理工具之sed http://www.linuxidc.com/Linux/2015-01/111436.htm