sed匹配第N個進行替換

sed -s '/^c/{:a;n;s@/bin/bash@/sbin/nologin0@g;/^m/!ba}' passwd

[root@elk 13_bash]# cat passwd
a:x:1002:1002::/home/a:/bin/bash
b:x:1003:1003::/home/b:/bin/bash
c:x:1004:1004::/home/c:/bin/bash
d:x:1005:1005::/home/d:/bin/bash
e:x:1006:1006::/home/e:/bin/bash
f:x:1007:1007::/home/f:/bin/bash
g:x:1008:1008::/home/g:/bin/bash
h:x:1009:1009::/home/h:/bin/bash
j:x:1010:1010::/home/j:/bin/bash
k:x:1011:1011::/home/k:/bin/bash
l:x:1012:1012::/home/l:/bin/bash
m:x:1013:1013::/home/m:/bin/bash
n:x:1014:1014::/home/n:/bin/bash
p:x:1015:1015::/home/p:/bin/bash
i:x:1016:1016::/home/i:/bin/bash
cc:x:1017:1017::/home/cc:/bin/bash
dd:x:1018:1018::/home/dd:/bin/bash
ee:x:1019:1019::/home/ee:/bin/bash
bb:x:1020:1020::/home/bb:/bin/bash
[root@elk 13_bash]# sed -s '/^c/{:a;n;s@/bin/bash@/sbin/nologin0@g;/^m/!ba}' passwd
a:x:1002:1002::/home/a:/bin/bash
b:x:1003:1003::/home/b:/bin/bash
c:x:1004:1004::/home/c:/bin/bash
d:x:1005:1005::/home/d:/sbin/nologin0
e:x:1006:1006::/home/e:/sbin/nologin0
f:x:1007:1007::/home/f:/sbin/nologin0
g:x:1008:1008::/home/g:/sbin/nologin0
h:x:1009:1009::/home/h:/sbin/nologin0
j:x:1010:1010::/home/j:/sbin/nologin0
k:x:1011:1011::/home/k:/sbin/nologin0
l:x:1012:1012::/home/l:/sbin/nologin0
m:x:1013:1013::/home/m:/sbin/nologin0
n:x:1014:1014::/home/n:/bin/bash
p:x:1015:1015::/home/p:/bin/bash
i:x:1016:1016::/home/i:/bin/bash
cc:x:1017:1017::/home/cc:/bin/bash
dd:x:1018:1018::/home/dd:/sbin/nologin0
ee:x:1019:1019::/home/ee:/sbin/nologin0
bb:x:1020:1020::/home/bb:/sbin/nologin0
[root@elk 13_bash]#

sed匹配第N個進行替換
怎麼匹配開頭c到開頭m(開始結束字符串確定),然後替換/bin/bash爲/sbin/nologin0這樣的
先匹配開頭c,匹配到後執行大括號裏的語句。
n 讀取下一行
s@/bin/bash@/sbin/nologin0@g 將/bin/bash替換爲/sbin/nologin0,全局替換,同一行中出現幾次替換幾次
:a 設定跳轉標籤a
/^m/!ba 若當前行匹配不上開頭m,則跳轉到標籤a處繼續執行,構成一個循環。若匹配到開頭f,則退出循環,sed重新對讀入的每行匹配開頭c。
由於sed沒有加-n靜默選項,所以默認對每行數據處理後都打印。
其中:a和!ba中的a是可以隨意改變的,其中的b是不可改變的.


例:轉載於:http://blog.uouo123.com/post/704.html
文本內容:
aa
88
bb
88
88
cc
88
88
替換第一個88爲--:
sed '0,/88/s//--/' file
sed ':a;N;$!ba;s/88/--/' file

[解析] 這有兩種方法,
第一個是隻匹配到第一個88爲止,然後替換那個88爲--。
第二個句子是通過循環把文本全部讀進pattern space 然後只替換第一個。
替換第N[3]個88爲--:
sed '/88/{x;s/^/./;/^.{3}$/{x;s/./--/;x};x;}' file
sed ':a;N;$!ba;s/88/--/3' file
[解析]
第一個命令叫打點記數法,因爲sed沒有 var++ 之類的操作來記數。
第二個命令和上面第一個其實是一樣的原理,全部讀入文本後統一替換第3個匹配的內容。
替換最後一個匹配的88爲--:
sed ':a;/\n88/!{$s/88/--/;N;ba};P;D' file
sed ':a;N;$!ba;s/(.
)88/\1--/' file

[解析]
第一個命令,沒匹配到 /\n88/ 的內容就讀取下一行,然後 ba 跳轉去開始處,如果讀取到88的行呢,就執行後面的 P;D 組合,D也有循環功能,一直把匹配 \n88 內容的第一行打印,刪除,直到不匹配/\n88/(因爲換行符已經被打印出去了,所以不再會匹配到 \n88),這時候才繼續往下讀,如果又讀到88的行,那麼又執行P;D循環,同上操作。一直到匹配到最後一個88的行,繼續讀取到末行時執行替換,N 因爲沒有下一行可讀,所以會自動中止命令,因爲沒有 -n 參數會打印 pattern space 裏的內容到屏幕,所以就不會再執行後面的 ba 避免了死循環,這樣的用法只存在於 GNU sed ,大家注意。所以這整個流程只會替換最後一個88。
第二個命令其實和上面的都一樣,也是全部讀進 pattern space 裏,最後利用正則的貪婪替換掉最後一個88。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章