與vim
不一樣,sed
是一種非交互式的文本編輯器,同時它又是面向字符流的,每行數據通過sed
處理後輸出。ios
sed [OPTION]... [script] [file]...
sed
的工做過程是這樣的:首先,初始化兩個數據緩衝區模式空間
和保持空間
;sed
讀取一行輸入(來自標準輸入或文件),去掉結尾的換行符(\n)後置於模式空間中,而後針對模式空間中的字符串開始執行‘sed命令’,每一個命令均可以有地址
與之相關聯,地址能夠當作是條件,只有在條件成立時,相關的命令才被執行;全部可執行命令都處理完畢後,仍處於模式空間中的字符串會被追加一個換行符後打印輸出;以後讀取下一行輸入作一樣的處理,直到主動退出(q)或輸入結束。正則表達式
地址
能夠是以下的形式vim
一、number
表示行號
二、first~step
表示從first(數字)行開始,每隔step(數字)行
三、$
表示最後一行(注意當出如今正則表達式中時表示行尾)
四、/regexp/
表示匹配正則表達式regexp(關於正則表達式,請參見這一篇)
五、\%regexp% 表示匹配正則表達式regexp,%能夠換成任意其餘單個字符。(用於regexp包含斜線/的狀況)
六、/regexp/I
匹配正則表達式regexp時不區分大小寫
七、/regexp/M
啓用正則多行模式,使$不止匹配行尾,還匹配\n或\r以前的位置;使^不止匹配行首,還匹配\n或\r以後的位置。此時能夠用(\`)匹配模式空間的開頭位置,用(\')匹配模式空間的結束位置。segmentfault
還能夠用逗號
,
分隔兩個地址來表示一個範圍windows
表示從匹配第一個地址開始,直到匹配第二個地址或文件結尾爲止。若是第二個地址是個正則表達式,則不會對第一個地址匹配行進行第二個地址的匹配;若是第二個地址是行號,但小於或等於第一個地址匹配行行號,則只會匹配一行(第一個地址匹配行)。centos
八、0,/regexp/
這種狀況下,正則表達式regexp會在第一行就開始進行匹配。只有第二個地址是正則表達式時,第一個地址才能用0。
九、addr1,+n
表示匹配地址addr1和其後的n行。
十、addr1,~n
表示從匹配地址addr1開始,直到n的倍數行爲止。
若是沒有給出地址,全部的行都會匹配;在地址或地址範圍後追加字符!
表示對地址取反,全部不匹配的行纔會被處理。bash
-n
默認時每一行處理過的字符串都會被打印輸出,此選項表示關閉此默認行爲。只有被命令p
做用的字符串纔會被輸出。-f file
表示從file中讀取sed命令-i
表示原地修改。應用此選項時,sed
會建立一個臨時文件,並將處理結果輸出到此文件,處理完畢後,會將此臨時文件覆蓋至原文件。-r
表示使用擴展的正則表達式編輯器
p
表示打印模式空間內容,一般配合選項-n
一塊兒使用centos7
[root@centos7 ~]# seq 5 1 2 3 4 5 [root@centos7 ~]# 只輸出第二行到第四行 [root@centos7 ~]# seq 5|sed -n '2,4p' 2 3 4 [root@centos7 ~]#
d
刪除模式空間內容,當即處理下一行輸入。code
#刪除最後一行 [root@centos7 ~]# seq 5|sed '$d' 1 2 3 4 [root@centos7 ~]#
q
當即退出,再也不處理任何命令和輸入(只接受單個地址)
[root@centos7 ~]# seq 5|sed '/3/q' 1 2 3 [root@centos7 ~]#
n
若是沒有使用選項-n
,輸出模式空間中內容後,讀取下一行輸入並覆蓋當前模式空間內容。若是沒有更多的輸入行,sed會退出執行。
[root@centos7 ~]# seq 9|sed -n 'n;p' 2 4 6 8 [root@centos7 ~]# 注意多個命令用分號分隔
s/regexp/replacement/flag
表示用replacement替換模式空間中匹配正則表達式regexp的部分。在這裏符號/
能夠換成任意單個字符。
[root@centos7 ~]# echo "hello123world"|sed 's/[0-9]\+/,/' hello,world #注意這裏+須要轉義,若是使用選項-r則無需轉義
在replacement中
一、\n (n爲1-9中的一個數字)表示對正則表達式中分組(...)
的引用;
[root@centos7 ~]# echo "hello123world"|sed -r 's/[a-z]+([0-9]+)[a-z]+/\1/' 123 [root@centos7 ~]# echo "hello123world"|sed -r 's/([a-z]+)[0-9]+([a-z]+)/\1,\2/' hello,world
二、&
表示模式空間中全部匹配regexp的部分;
[root@centos7 ~]# echo "hello123world"|sed -r 's/[0-9]+/:&:/' hello:123:world
三、\L 將後面的字符轉化成小寫直到 \U 或 \E 出現;
四、\l 將下一個字符轉化爲小寫;
五、\U 將後面的字符轉化成大寫直到 \L 或 \E 出現;
六、\u 將下一個字符轉化爲大寫;
七、\E 中止由 \L 或 \U 起始的大小寫轉化;
[root@centos7 ~]# echo "hello123world"|sed -r 's/^([a-z]+)[0-9]+([a-z]+)$/\U\1\E,\u\2/' HELLO,World [root@centos7 ~]#
flag
一、n
數字n表示替換第n個匹配項
[root@centos7 ~]# head -1 /etc/passwd root:x:0:0:root:/root:/bin/bash #替換冒號分隔的第五部分爲空 [root@centos7 ~]# head -1 /etc/passwd|sed 's/[^:]\+://5' root:x:0:0:/root:/bin/bash
二、g
表示全局替換
[root@centos7 ~]# echo "hello123world"|sed 's/./\U&\E/' Hello123world [root@centos7 ~]# [root@centos7 ~]# echo "hello123world"|sed 's/./\U&\E/g' HELLO123WORLD [root@centos7 ~]# #當數字n和g同時使用時,表示從第n個匹配項開始替換一直到最後匹配項 [root@centos7 ~]# head -1 /etc/passwd|sed 's/[^:]\+://4g' root:x:0:/bin/bash/
三、p
表示若是替換成功,則打印模式空間內容。
四、w file
表示若是替換成功,則輸出模式空間內容至文件file中。
五、I
和i
表示匹配regexp時不區分大小寫。
[root@centos7 ~]# echo 'HELLO123world'|sed -r 's/[a-z]+//Ig' 123 [root@centos7 ~]#
六、M
和m
表示啓用正則多行模式(如前所述)。(講命令N
時再舉例)
y/source-chars/dest-chars/
把source-chars中的字符替換爲dest-chars中對應位置的字符,/
能夠換爲其餘任意單個字符,source-chars和dest-chars中字符數量必須一致且不能用正則表達式。
[root@centos7 ~]# echo hello|sed 'y/el/LE/' hLEEo [root@centos7 ~]#
a text
表示輸出模式空間內容後追加輸出text內容
[root@centos7 ~]# seq 3|sed '1,2a hello' 1 hello 2 hello 3 [root@centos7 ~]#
i text
表示輸出模式空間內容以前,先輸出text內容
[root@centos7 ~]# seq 3|sed '$ihello' 1 2 hello 3 [root@centos7 ~]#
c text
表示刪除匹配地址或地址範圍的模式空間內容,輸出text內容。若是是單地址,則每一個匹配行都輸出,若是是地址範圍,則只輸出一次。
[root@centos7 ~]# seq 5|sed '1,3chello' hello 4 5 [root@centos7 ~]# seq 5|sed '/^[^3-4]/c hello' hello hello 3 4 hello
=
表示打印當前輸入行行號
[root@centos7 ~]# seq 100|sed -n '$=' 100 [root@centos7 ~]# seq 100|sed -n '/^10\|^20/=' 10 20 100 [root@centos7 ~]# 轉義的|表示邏輯或
r file
表示讀取file的內容,並在當前模式空間內容輸出以後輸出
[root@centos7 ~]# cat file hello world [root@centos7 ~]# seq 3|sed '1,2r file' 1 hello world 2 hello world 3 [root@centos7 ~]#
w file
表示輸出模式空間內容至file中
N
讀入一行內容至模式空間後,再追加下一行內容至模式空間(此時模式空間中內容形如 line1\nline2 ),若是不存在下一行,sed
會退出。
[root@centos7 ~]# seq 10|sed -n 'N;s/\n/ /p' 1 2 3 4 5 6 7 8 9 10 [root@centos7 ~]# #s命令的m flag舉例 [root@centos7 ~]# seq 3|sed 'N;s/^2/xxx/' 1 2 3 [root@centos7 ~]# seq 3|sed 'N;s/^2/xxx/m' 1 xxx 3 [root@centos7 ~]# seq 3|sed 'N;s/1$/xxx/' 1 2 3 [root@centos7 ~]# seq 3|sed 'N;s/1$/xxx/M' xxx 2 3
D
若是模式空間中沒有新行(如命令N
產生的新行),則和命令d
起一樣做用;若是包含新行,則會刪除第一行內容,而後對模式空間中剩餘內容從新開始一輪處理。(注意:D後面的命令將會被忽略)
[root@centos7 ~]# seq 5|sed 'N;D' 5 [root@centos7 ~]# seq 5|sed 'N;N;D' 3 4 5
P
打印模式空間中第一行內容
[root@centos7 ~]# seq 10|sed -n 'N;P' 1 3 5 7 9 [root@centos7 ~]# seq 10|sed -n 'N;N;P' 1 4 7 #注意另外一種寫法輸出中的不一樣 [root@centos7 ~]# seq 10|sed -n '1~3P' 1 4 7 10
g
用保持空間中的內容替換模式空間中的內容
[root@centos7 ~]# seq 5|sed -n 'g;N;s/\n/xx/p' xx2 xx4 [root@centos7 ~]#
G
追加一個換行符到模式空間,而後再將保持空間中的內容追加至換行符以後。(此時模式空間中內容形如 PATTERN\nHOLD )
[root@centos7 ~]# seq 5|sed 'G;s/\n/xx/' 1xx 2xx 3xx 4xx 5xx
h
用模式空間中的內容替換保持空間中的內容(注意此時模式空間中的內容並無被清除)
[root@centos7 ~]# seq 5|sed -n 'h;G;s/\n/xx/p' 1xx1 2xx2 3xx3 4xx4 5xx5 [root@centos7 ~]# seq 5|sed -n 'h;G;G;s/\n/xx/gp' 1xx1xx1 2xx2xx2 3xx3xx3 4xx4xx4 5xx5xx5
H
追加一個換行符到保持空間,而後再將模式空間中的內容追加至換行符以後。(此時保持空間中內容形如 HOLD\nPATTERN )
[root@centos7 ~]# seq 3|sed -n 'H;G;s/\n/xx/gp' 1xxxx1 2xxxx1xx2 3xxxx1xx2xx3 [root@centos7 ~]#
x
交換模式空間和保持空間的內容
[root@centos7 ~]# seq 9|sed -n '1!{x;N};s/\n//p' 3 25 47 69 #處於{...}之中的是命令組
: label
爲分支命令指定標籤位置(不容許地址匹配)
b label
無條件跳轉到label分支,若是省略了label,則跳轉到整條命令結尾(即開始下一次讀入)
#如刪除xml文件中註釋部分(<!--...-->之間的部分是註釋,能夠多行) sed '/<!--/{:a;/-->/!{N;ba};d}' server.xml #表示匹配<!--開始,在匹配到-->以前一直執行N,匹配到-->以後刪除模式空間中內容 #如在nagios的配置文件中,有許多define host{...}的字段,以下所示: define host{ use windows-server host_name serverA hostgroups 060202 alias 060202 contact_groups yu address 192.168.1.1 } #如今須要刪除ip地址是192.168.1.1的段,能夠這樣: sed -i '/define host/{:a;N;/}/!ba;/192\.168\.1\.1/d}' file #注意和前一個例子中的區別
t label
在一次輸入後有成功執行的s
替換命令才跳轉到label,若是省略了label,則跳轉到整條命令結尾(即開始下一次讀入)
#如行列轉換 [root@centos7 ~]# seq 10|sed ':a;$!N;s/\n/,/;ta' 1,2,3,4,5,6,7,8,9,10 [root@centos7 ~]# #如將MAC地址78A35114F798改爲帶冒號的格式78:A3:51:14:F7:98 [root@centos7 temp]# echo '78A35114F798'|sed -r ':a;s/\B\w{2}\b/:&/;ta' 78:A3:51:14:F7:98 [root@centos7 temp]# #這裏\b表示匹配單詞邊界,\B表示匹配非單詞邊界的其餘任意字符 #固然也能夠採用其餘的方式實現: [root@centos7 temp]# echo '78A35114F798'|sed -r 's/..\B/&:/g' 78:A3:51:14:F7:98 [root@centos7 temp]#
T label
在一次輸入後只要沒有替換命令被成功執行就跳轉到label,若是省略了label,則跳轉到整條命令結尾(即開始下一次讀入)
z
表示清除模式空間中內容,和s/.*//
起相同的做用,但更有效。
#例如輸入數據爲命令seq 10的輸出(固然也能夠是任意其餘文件內容) #要求刪除匹配5那一行的前一行和後一行 [root@centos7 temp]# seq 10|sed -n '$!N;/\n5/{s/.*\n//p;N;d};P;D' 1 2 3 5 7 8 9 10
#輸入數據爲命令seq 11的輸出,要求分別將奇數和偶數分別放在同一行 #輸出第一行`1 3 5 7 9 11`,第二行`2 4 6 8 10` [root@centos7 ~]# seq 11|sed -nr '$!N;2!G;s/([^\n]+)\n((.+)\n)?(.+)\n(.+)/\4 \1\n\5 \3/;h;$p' 1 3 5 7 9 11 2 4 6 8 10 [root@centos7 ~]#
#文本a.txt的內容: 01 12510101 4001 02 12310001 4002 03 12550101 4003 04 12610001 4004 05 12810001 4005 06 12310001 4006 07 12710001 4007 08 12310001 4008 09 12810101 4009 10 12510101 4010 11 12310001 4011 12 12610001 4012 13 12310001 4013 #文本b.txt的內容: A 12410101 2006/02/15 2009/01/31 4002 B 12310001 2006/08/31 2008/08/29 4001 C 12610001 2008/05/23 2008/05/22 4002 D 12810001 1992/12/10 1993/06/30 4001 E 12660001 1992/05/11 1993/06/01 4005 #要求輸出a.txt內容中第二列和b.txt中第二列相同的行,並追加b.txt中對應的兩個日期列。 #形如:02 12310001 4002 2006/08/31 2008/08/29 sed -rn '/^[01]/ba;H;:a;G;s/^((..)( .*)( [^\n]+)).*\3(( [^ ]*){2}).*/\1\5/p' b.txt a.txt #固然若是使用awk來處理的話,解決思路更容易理解一些: awk 'NR==FNR{a[$2]=$3FS$4;next}{if($2 in a)print $0,a[$2]}' b.txt a.txt
爲加深對sed各類命令特性的理解,請自行分析這三個例子。
各類命令的組合使用,再加上正則表達式的強大能力,使得sed
能夠處理全部可以計算的問題。但因爲代碼可讀性不強,理解起來比較困難,一般使用sed
做爲一個文本編輯器,對文本作非交互的流式處理。理解上述各個命令的含義,熟練使用它們,就會發現sed
的強大之處。