1. 程式人生 > 其它 >Linux shell 知識心得09 三劍客之sed

Linux shell 知識心得09 三劍客之sed

三劍客之sed命令

一 sed介紹

​ sed全稱(stream editor)流式編輯器,Sed主要用來自動編輯一個或多個檔案、簡化對檔案的反覆操作、編寫轉換程式等,工作流程如下

sed 是一種線上的、非互動式的編輯器,它一次處理一行內容。處理時,把當前處理的行儲存在
臨時緩衝區中,稱為“模式空間”(pattern space),接著用sed命令處理緩衝區中的內容,處理完
成後,把緩衝區的內容送往螢幕。接著處理下一行,這樣不斷重複,直到檔案末尾。檔案內容並沒有
改變,除非你使用重定向儲存輸出,或者使用sed -i選項
-i選項就是將本該輸出到螢幕上的內容輸出/流入檔案中

​ sed命令格式如下

sed [options] 'command' file(s)
sed [options] -f scriptfile file(s)

# 注:
sed和grep不一樣,不管是否找到指定的模式,它的退出狀態都是0
只有當命令存在語法錯誤時,sed的退出狀態才不是0

二 sed選項與基本用法示例

2.1 sed選項

選項			   功能
-e				允許多項編輯
-n				取消預設的輸出(模式空間的內容輸出)
-i				inplace,就地編輯
-r				支援擴充套件元字元
-f				指定sed指令碼檔名

示例
# sed -r '' /etc/passwd
# sed -r 'p' /etc/passwd
# sed -r -n 'p' /etc/passwd	


檔案的一行行內容相當與水流,連續兩個-e就是設定了兩道關卡
[root@aliyun ~]# sed '' test.txt 
1111111
2222222simon
333333simon
444444simon
555555eon
[root@aliyun ~]# sed -e '3d' -e '1d' test.txt  
2222222simon
444444simon
555555eon
[root@aliyun ~]# sed -rn -e '1,3d' -e 'p' test.txt
444444simon
555555eon
[root@aliyun ~]# 

也可以將多道關卡寫入一個檔案中
[root@aliyun ~]# cat sed.txt 
1,3d
p
[root@aliyun ~]# sed -rn -f sed.txt test.txt
444444simon
555555eon
[root@aliyun ~]# 

2.2 sed命令組成

命令由”地址+命令“兩部分組成,命令如p、d,更多詳解第三章節,本節我們主要介紹地址

地址用於決定對流入模式空間的哪些行進行編輯,如果沒有指定地址,sed將處理流入模式空間的所有行。

地址可以是

  • 1、數字

    sed -n 'p' /etc/passwd	
    sed -n '1,3p' /etc/passwd	
    sed '1,47d' /etc/passwd
    
  • 2、正則表示式

    與grep一樣,sed在檔案中查詢模式時也可以使用正則表示式(RE)和各種元字元。正則表示式是
    括在斜槓間的模式,用於查詢和替換,以下是sed支援的元字元。
    
    # 使用基本元字符集	
    ^, $, ., *, [], [^], \< \>,\(\),\{\}
    
    # 使用擴充套件元字符集	
    ?, +, { }, |, ( )
    
    # 使用擴充套件元字元的方式:
    轉義,如\+
    -r引數,如sed -r
    
    [root@aliyun ~]# cat test.txt 
    1111111
    2222222egon
    333333egon
    444444egon
    555555eon
    [root@aliyun ~]# sed -rn '/egon/p' test.txt 
    2222222egon
    333333egon
    444444egon
    [root@aliyun ~]# 
    
  • 3、數字+正則表示式

    [root@aliyun ~]# cat test.txt 
    1111111
    2222222egon
    333333egon
    444444egon
    555555eon
    [root@aliyun ~]# sed -rn '1,/egon/p' test.txt 
    1111111
    2222222egon
    [root@aliyun ~]# 
    
    解釋:
    # "1,8p"代表列印1到8行,"1,/egon/p"則代表取從第1行到首次匹配到/egon/的行
    

2.3 /cregexpc

地址可以是正則表示式,而正則表示式需要放置在\c與c中間,其中c可以是任意字元,但必須要加\轉義

[root@aliyun ~]# cat test.txt 
1111111
2222222egon
333333egon
444444egon
555555eon
[root@aliyun ~]# sed -rn '#egon#p' test.txt 
[root@aliyun ~]# sed -rn '\#egon#p' test.txt 
2222222egon
333333egon
444444egon
[root@aliyun ~]# 

如果c是左斜槓,不需要轉義也可以

[root@aliyun ~]# sed -rn '\/egon/p' test.txt 
2222222egon
333333egon
444444egon
[root@aliyun ~]# sed -rn '/egon/p' test.txt 
2222222egon
333333egon
444444egon
[root@aliyun ~]# 

如果匹配的正則裡有左斜槓,要麼將正則轉義,要麼將c轉義

[root@aliyun ~]# cat a.txt 
/etc/egon/666
etc
[root@aliyun ~]# sed -rn '//etc/egon/666/p' a.txt # 錯誤
sed: -e expression #1, char 0: no previous regular expression
    
[root@aliyun ~]# sed -rn '/\/etc\/egon\/666/p' a.txt  # 正則轉義
/etc/egon/666

[root@aliyun ~]# sed -rn '#/etc/egon/666#p' a.txt # 轉義c,必須是\c
[root@aliyun ~]# sed -rn '\#/etc/egon/666#p' a.txt  # 轉義c
/etc/egon/666
[root@aliyun ~]# 


# 示例
[root@aliyun ~]# cat a.txt 
/etc/egon/666
etc
[root@aliyun ~]# sed -ri '/\/etc\/egon\/666/s/.*/xxx/' a.txt 
[root@aliyun ~]# cat a.txt 
xxx
etc
[root@aliyun ~]# 

三 sed常用命令

sed命令告訴sed對指定行進行何種操作,包括列印、刪除、修改等。

命令			   功能
a				在當前行後新增一行或多行
c				用新文字修改(替換)當前行中的文字
d				刪除行
i				在當前行之前插入文字
l				會用$符號標識出文件中看不到的字元的位置
p				列印行
n				把下一行內容讀入模式空間,後續的處理命令處理的都是剛讀入的新內容
q				結束或退出sed,不會將後續內容讀入模式空間
r				從檔案中讀
!				對所選行以外的所有行應用命令
s				用一個字串替換另一個
w				將行寫入檔案
y				將字元轉換為另一字元(不支援正則表示式),y/egon/1234/  e->1 g->2 o->3 n->4
h				把模式空間裡的內容複製到暫存緩衝區(覆蓋)
H				把模式空間裡的內容追加到暫存緩衝區
g				取出暫存緩衝區的內容,將其複製到模式空間,覆蓋該處原有內容
G				取出暫存緩衝區的內容,將其複製到模式空間,追加在原有內容後面
x				交換暫存緩衝區與模式空間的內容

替換標誌 s
g				在行內進行全域性替換
i				忽略大小寫

sed命令示例

列印命令:p
# sed -r "/egon/p" a.txt		
# sed -r -n "/egon/p" a.txt

刪除命令:d,注意用單引號
# sed -r '3d' a.txt
# sed -r '3,$d' a.txt
# sed -r '$d' a.txt
# sed -r '/egon/d' a.txt 	
# sed -r '1,/egon/{/egon/d}' a.txt 			# 只刪除模式匹配成功的第一行


[root@egon ~]# cat a.txt 
Egon111111
egon222222
333Egon333
444444egon
5555555555
6666666666
egon777777
8888888888
[root@egon ~]# 
[root@egon ~]# sed -r '/egon/d' a.txt  # 只刪除模式匹配成功的所有行
Egon111111
333Egon333
5555555555
6666666666
8888888888
[root@egon ~]# sed -r '1,/egon/{/egon/d}' a.txt  # 只刪除模式匹配成功的第一行
Egon111111
333Egon333
444444egon
5555555555
6666666666
egon777777
8888888888


替換命令:s
# sed -r 's/egon/Bigegon/' a.txt 
# sed -r 's/egon/Bigegon/g' a.txt 
# sed -r 's/^egon/Bigegon/g' a.txt
# sed -r -n 's/root/egon/gip' /etc/passwd
# sed -r 's/[0-9]$/&.change/' a.txt		# &代表取到匹配成功的整行內容

# sed -r 's/^([a-zA-Z]+)([^[a-zA-Z]+)/\2\1/' a.txt
# sed -r 's#egon#bigegon#g' a.txt			

多重編輯命令:e
# sed -r -e '1,3d' -e 's/[Ee]gon/EGON/g' a.txt  # 在前一個-e的基礎之上進行第二個-e操作
# sed -r '1,3d;s/[Ee]gon/EGON/g' a.txt

# sed -r '3{s/[0-9]/x/g;s/[Ee]gon/EGON/g}' a.txt  # 只處理第三行
# sed -r '1,3{s/[0-9]/x/g;s/[Ee]gon/EGON/g}' a.txt  # 處理1到3行

# sed -r -n '1p;p' a.txt  # ;分隔依次執行,先針對第一行進行p操作,再針對所有行進行p操作
# sed -r -n '1{p;p}' a.txt  # 只針對第一行,連續進行兩次p操作

反向選擇!
# sed -r '3d' a.txt
# sed -r '3!d' a.txt


讀檔案命令:r
# sed -r '/^Egon/r b.txt' a.txt  # 在匹配成功的行後新增檔案b.txt的內容
# sed -r '/2/r b.txt' a.txt  # 在第2行後面新增檔案b.txt的內容

寫檔案命令:w
# sed -r '/[Ee]gon/w b.txt' a.txt  # 將匹配成功的行寫入新檔案b.txt		
# sed -r '3,$w /root/new.txt' a.txt # 將第3行到最後一行寫入/root/new.txt

追加命令:a
# sed -r '2aXXXXXXXXXXXXXXXXXXXX' a.txt  # 在第2行後新增一行
# sed -r '2a1111111111111\               # 可以用\續行
> 222222222222\
> 333333333333' a.txt

插入命令:i
# sed -r '2i1111111111111' /etc/hosts
# sed -r '2i111111111\
> 2222222222\
> 3333333333' a.txt

修改命令:c
# sed -r '2c1111111111111' a.txt
# sed -r '2c111111111111\
> 22222222222\
> 33333333333' a.txt

把下一行內容讀入模式空間:n
# sed -r '/^Egon/{n;s/[0-9]/x/g}' a.txt  # 將匹配/^Egon/成功的行的下一行讀入模式空間進行s處理
[root@aliyun ~]# cat a.txt 
/etc/egon/666
etc
[root@aliyun ~]# sed -r '\#/etc/egon/666#n;c 1111' a.txt 
/etc/egon/666
1111
[root@aliyun ~]# 

轉換命令:y
# sed -r '1,3y/Eeo/12X/' a.txt  # 1到3行進行轉換 對應規則:a->1 e->2 o->X

退出:q
# sed -r '5q' a.txt 			
# sed -r '/[Ee]gon/{ s/[0-9]/X/; q; }' a.txt  # 匹配成功/[Ee]gon/則執行{}內命令,q代表退出,即替換一次則退出,如果檔案中多行符合規則的內容也只替換了第一個

四 模式空間與保持空間

sed 有兩個內建的儲存空間:

  • 模式空間(pattern space):

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

  • 保持空間(hold space):

    保持空間是另外一個緩衝區,用來存放臨時資料。Sed 可以在保持空間和模式空間交換資料,但是不能在保持空間上執行普通的 sed 命令。

我們已經討論過,每次迴圈讀取資料過程中,模式空間的內容都會被清空,然而保持空間的內容則保持不變,不會在迴圈中被刪除。

模式空間與保持空間的操作命令

x:命令x(exchange) 用於交換模式空間和保持空間的內容

h:模式空間複製/覆蓋到保持空間
H:模式空間追加到保持空間

g:保持空間複製/覆蓋到模式空間
G:保持空間追加到模式空間

n:讀取下一行到/覆蓋到模式空間
N:將下一行新增到模式空間


d:刪除pattern space中的所有行,並讀入下一新行到pattern space中

示例:交換檔案的行

[root@egon ~]# cat test.txt 
1111
2222
3333

# ======================方式1:======================
[root@egon ~]# tac test.txt 
3333
2222
1111
[root@egon ~]# 

# ======================方式2:======================
思路:
# 1、讀取檔案第一行內容到模式空間,進行的操作如下  
# 將模式空間內容覆蓋到保持空間
# 刪除模式空間內容
   
# 2、讀取檔案第二行內容到模式空間,進行的操作如下  
# 將保持內容追加到模式空間
# 將模式空間內容覆蓋到保持空間
# 刪除模式空間內容 

# 3、讀取檔案第三行內容到模式空間,進行的操作如下  
# 將保持空間內容追加到模式空間

實現:
sed -r '1h;1d;2G;2h;2d;3G' test.txt
或者
sed '1!G;h;$!d' test.txt

五 sed指令碼

sed指令碼就是寫在檔案中的一系列sed命令,使用-f 選項指定sed指令碼檔名,需要注意的問題如下

  • 指令碼末尾不能有任何多餘的空格或文字
  • 如果命令不能獨佔一行,就必須以\結尾
  • 指令碼中不能使用引號,除非它們是查詢串的一部分
  • 反斜槓起到續行的作用
[root@egon ~]# cat sed.sh #永久儲存,存了多行sed命令,相當於多道關卡,每讀入一行內容將經歷一道道關卡
1h;1d;2G;2h;2d;3G
1h;1d;2G;2h;2d;3G

[root@egon ~]# sed -r '' a.txt
1111
2222
3333
[root@egon ~]# 
[root@egon ~]# sed -r -f sed.sh test.txt 
3333
2222
1111
2222
1111
[root@egon ~]# 

六 練習

刪除配置檔案中用井號#註釋的行
sed -r -i '/^#/d' file.conf 
sed -r -i '/^[ \t]*#/d' file.conf

刪除配置檔案中用雙斜槓//註釋的行 
sed -r -i '\c//cd' file.conf

刪除無內容空行 
sed -r '/^$/d' file.conf 
sed -r '/^[\t]*$/d' file.conf 
sed -r '/^[ \t]*$/d' file.conf


示例:
# 刪除#號註釋和無內容的空行
sed -r -i '/^[ \t]*#/d; /^[ \t]*$/d' /etc/vsftpd/vsftpd.conf
sed -r -i '/^[ \t]*#|^[ \t]*$/d' /etc/vsftpd/vsftpd.conf # 同上

追加一行,\可有可無,有更清晰
sed -r -i '$a\chroot_local_user=YES' /etc/vsftpd/vsftpd.conf 


給檔案每行加註釋
sed -r -i 's/^/#/' filename

每指定行加註釋
sed -r -i '10,$s/^/#/' filename
sed -r '3,$s/^#*/#/' filename		# 將行首連續的零個或多個#換成一個#


sed中使用外部變數
# var1=666
# sed -r 3a$var1 test.txt    # 可以不加引號
# sed -r "3a$var1" test.txt  # 也可以加引號,但注意是雙引號而不是單引號,因為要用$符號取變數值
# sed -r '3a'"$var1" test.txt # 也可以sed命令用''引起來,而變數用"",注意二者之間不能有空格