sed 是在 UNIX ® 操作系統(tǒng)上運(yùn)行的一個(gè)非交互式上下文編輯器。sed 被設(shè)計(jì)在下列三種情況下發(fā)揮作用:
1) 編輯那些對舒適的交互式編輯而言太大的文件。
2) 在編輯命令太復(fù)雜而難于在交互模式下鍵入的時(shí)候編輯任何大小的文件。
3) 要在對輸入的一趟掃描中有效的進(jìn)行多個(gè)‘全局’編輯函數(shù)。
因?yàn)槊看沃话演斎氲哪承┬旭v留在內(nèi)存中,并且不使用臨時(shí)文件,所以可編輯的文件的有效大小,只受限于輸入和輸出要同時(shí)共存于次級(jí)存儲(chǔ)的要求。
可以單獨(dú)的建立復(fù)雜的編輯腳本并作為給 sed 的命令文件。對于復(fù)雜的編輯,這節(jié)省了可觀的鍵入和隨之而來的錯(cuò)誤。從命令文件運(yùn)行 sed 高效于作者所知道的任何交互式編輯器,甚至包括能用預(yù)先寫好的腳本驅(qū)動(dòng)的編輯器。
sed是如何操作的?
sed 缺省的把標(biāo)準(zhǔn)輸入復(fù)制到標(biāo)準(zhǔn)輸出,再把每行寫到輸出之前可能在其上進(jìn)行一個(gè)或多個(gè)編輯命令。這種行為可以通過命令行上的標(biāo)志來更改。
sed編輯命令的一般格式為:
[address]command [parameter]
一個(gè)或兩個(gè)[address]是可以省略的;可以用任何數(shù)目的空白或 tab 把地址和函數(shù)分隔開。sed函數(shù)必須出現(xiàn)。依據(jù)給出的是哪個(gè)函數(shù),參數(shù)可能是必需的或是可選的。忽略在這些行開始處的 tab 字符和空格。
sed如何對文件的行操作的步驟?
1)sed對[address]里匹配的行,執(zhí)行命令并輸出在stdout。
2)sed在對匹配的行的執(zhí)行完所有命令后,自動(dòng)跳到下一個(gè)匹配行重復(fù)命令執(zhí)行。
3)sed對文本行的操作,并不會(huì)更改文本的行內(nèi)容。sed是從文本中調(diào)出行內(nèi)容,并備份,然后在這備份上執(zhí)行sed命令,最終在stdout上輸出操作后的行。
sed命令行格式和標(biāo)志:
sed命令格式:sed [option] 'sed-script' file
在命令行上option:
* -n:告訴 sed 不復(fù)制所有的行,只復(fù)制 p 函數(shù)或在 s 函數(shù)后 p 標(biāo)志所指定的行。
* -e:告訴 sed 把下一個(gè)參數(shù)接受為編輯命令。
* -f:告訴 sed 把下一個(gè)參數(shù)接受為文件名;這個(gè)文件應(yīng)當(dāng)包含一行一個(gè)的編輯命令。
什么是模式空間?
模式匹配的范圍叫做模式空間。一般而言,模式空間是輸入文本中某一行,但是可以通過使用 N 命令把多于一行讀入模式空間
sed如何從輸入文件里選擇編輯的行?
編輯命令要應(yīng)用于其上的,輸入文件中的行可以通過地址來選擇。地址可以是行號(hào)或者是上下文地址。
通過用花括號(hào)(‘{ }’)組合(group)命令,可以用一個(gè)地址(或地址對)來控制一組命令的應(yīng)用。
sed的行號(hào)是十進(jìn)制整數(shù)。在從輸入讀入每一行的時(shí)候,增加一個(gè)行號(hào)計(jì)數(shù)器;行號(hào)地址匹配(選擇)導(dǎo)致這個(gè)內(nèi)部計(jì)數(shù)器等于地址行號(hào)的輸入行。計(jì)數(shù)器在多個(gè)輸入文件上累計(jì)運(yùn)行,在打開一個(gè)新文件的時(shí)候它不被復(fù)零(reset)。
作為特殊情況,字符 $ 匹配輸入文件的最后一行。
上下文地址是包圍在斜杠中(‘/’)的模式(‘正則表達(dá)式’)。sed 識(shí)別的正則表達(dá)式被構(gòu)造如下:
* 1) 普通字符(不是下面討論的某個(gè)字符)是一個(gè)正則表達(dá)式,并且匹配這個(gè)字符。
* 2) 在正則表達(dá)式開始處的‘^’符號(hào)(circumflex)匹配在行開始處的空(null)字符。
* 3) 在正則表達(dá)式結(jié)束處的美元符號(hào)‘$’匹配在行結(jié)束處的空字符。
* 4) 字符‘"n’匹配內(nèi)嵌的換行字符,而不是在模式空間結(jié)束處的換行。
* 5) 點(diǎn)‘.’匹配除了模式空間的終止換行之外的任何字符。
* 6) 跟隨著星號(hào)‘*’的正則表達(dá)式,匹配它所跟叢的正則表達(dá)式的任何數(shù)目(包括 0)的毗連出現(xiàn)。
* 7) 在方括號(hào)‘[ ]’內(nèi)的字符串,匹配在字符串內(nèi)的任何字符,而非其他。但是如果這個(gè)字符串的第一個(gè)字符是‘^’符號(hào),正則表達(dá)式匹配除了在這個(gè)字符串內(nèi)的字符和模式空間的終止換行之外的任何字符。
* 8) 正則表達(dá)式的串聯(lián)(concatenation)是正則表達(dá)式,它匹配這個(gè)正則表達(dá)式的成員所匹配的字符串的串聯(lián)。
* 9) 在順序的‘"(’和‘")’之間的正則表達(dá)式,在效果上等同于沒有它修飾的正則表達(dá)式,但它有個(gè)副作用,將在下面的 s 命令和緊后面的規(guī)定 10 中描述。
* 10) 表達(dá)式‘"d’意味著與在同一個(gè)表達(dá)式中先前的‘"(’和‘")’中包圍的表達(dá)式所匹配的那些字符同樣的字符串。這里的 d 是一個(gè)單一的數(shù)字;指定的字符串是‘"(’的從左至右的第 d 個(gè)出現(xiàn)所起始的字符串。例如,表達(dá)式‘^"(.*")"1’匹配開始于同一個(gè)字符串的兩次重復(fù)出現(xiàn)的行。
* 11) 孤立的空正則表達(dá)式(就是‘//’)等價(jià)于編譯的最后一個(gè)正則表達(dá)式。
注意:要使用正則表達(dá)式的元字符(^ $ . * [ ] " /)中的某一個(gè)字符作為文字(去匹配輸入中它們自身的出現(xiàn)),要對這個(gè)特殊字符前導(dǎo)一個(gè)反斜杠‘"’。
有的sed命令可能有 0,1 或 2 個(gè)地址。在每個(gè)命令中都給出了允許的地址的最大數(shù)目。地址多于最大允許個(gè)數(shù)的命令被認(rèn)為是錯(cuò)誤的。
如果命令沒有地址,它應(yīng)用于輸入中每個(gè)行。
如果命令有一個(gè)地址,它應(yīng)用于匹配這個(gè)地址的所有行。
如果命令有兩個(gè)地址,它應(yīng)用于匹配第一個(gè)地址的第一行,和直到(并包括)匹配第二個(gè)地址的第一個(gè)后續(xù)行的所有后續(xù)行。接著在后續(xù)的行上再次嘗試匹配第一個(gè)地址,并重復(fù)這個(gè)處理。兩個(gè)地址用逗號(hào)分隔。
例子:
/an/ 匹配我們樣例文本的第 1, 3, 4 行
/an.*an/ 匹配第 1 行
/^an/ 沒有匹配行
/./ 匹配所有行
/"./ 匹配第 5 行
/r*an/ 匹配第 1,3, 4 行(number = zero!)
/"(an").*"1/ 匹配第 1 行
sed的命令格式:
[address1]command
或
[address1],[address2]command
前者表示sed對匹配地址的行進(jìn)行操作
后者表示sed對從匹配地址1的行到匹配地址2的行之間(包括地址1和地址2行)所有的行進(jìn)行操作
另外sed命令還可以用大括號(hào)進(jìn)行分組,使其作用于同一個(gè)地址:
[address]{
command1
command2
command3
}
或
[address]{command1;command2;command3}
注意:sed的[address]是正則表達(dá)式,并且要用/ /限定范圍,如:
/^$/,/^ */d
如果sed命令之間用;分隔,可以將多個(gè)命令寫在同一行,如:n;d;s/sdfd//g
sed腳本的注釋行第一個(gè)字符必須是"#"號(hào),如:
#wstar.scd:xxxx
sed的命令函數(shù):
sed命令集由25個(gè)命令組成,而且sed的命令大多是用單個(gè)字符表示。
n(讀取下一行)
[address]n
讀取[address]匹配行的下一行
n命令改變了正常的流控制,導(dǎo)致輸入的下一行取代模式空間中的當(dāng)前行,如:
/^".H1/{n;/^$/d} #將匹配匹配^".H1的下一空行刪除
=(打印行號(hào))
[address]=
在stdout,打印匹配的行號(hào),如:
/ if/{
=;p
}
p(打印行):
/address/p
在stdout,打印匹配的行
d(刪除):
[address]d
如果模行匹配address,那么就刪除整個(gè)這一行
[address1],[address2]d
刪除匹配address1和address2中間的所有行
注意:不允許在被刪除的行上做進(jìn)一步的操作
例子:
/^".sp/d
/^&/,/^".bp/d
a(追加新行):
[address]a"
text
在匹配address的行后追加新的text行。
注意:必須是a命令后跟一個(gè)"用于轉(zhuǎn)義第一個(gè)行尾,text必須從下一行開始。
例子:
/<larry's address>/a"
4700 Cross Court"
Freach tjck,IN
i(插入新行):
[address]ni"
text
表示在匹配address的行前插入新的text行。
或
ni"
text
表示在第n行插入新的text行
注意:必須是i命令后跟一個(gè)"用于轉(zhuǎn)義第一個(gè)行尾,text必須從下一行開始。
例子:
/<larry's address>/i"
4700 Cross Court
2i"
.so macros"
.ds CH first draft
q(退出命令):
[address]q
退出命令q會(huì)使sed停止讀取新的輸入行(并停止將他們發(fā)送到輸出)
/^".".$/q
或
nq
向stdout輸出1到(n-1)行的內(nèi)容,到第n行時(shí)退出sed
sed '100q' test
c(行更改):
[address]c"
text
或
[address1],[address2]c"
text
注意:必須是i命令后跟一個(gè)"用于轉(zhuǎn)義第一個(gè)行尾,text必須從下一行開始
c命令刪除當(dāng)前行并且在該位置放置所提供的文本。當(dāng)想要匹配行并整個(gè)取代它時(shí)使用c命令。
/^".sp/c"
.sp .5
/^From/,/^$/{
s/^From//p
c"
<Mail Header Removed>
}
y(轉(zhuǎn)換):
轉(zhuǎn)換語法:y/charators/change-charactors/
y的轉(zhuǎn)換是根據(jù)字符的位置來進(jìn)行的,//里用的不是正則表達(dá)式,只是一般的字符序列。它沒有詞的概念,只是簡單的將對應(yīng)位置上的字符作替換。
注意:charactors和change-charactors的字符數(shù)目要一致。
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
s(替換):
替換命令語法為[address]s/pattern/replacement/flags
修飾替換標(biāo)志flags是:
n 1-512之間的一個(gè)數(shù)字,表示在模式空間里對匹配pattern的字符串第n次出現(xiàn)后開始進(jìn)行替換,將替換后的行輸出stdout
g 對模式空間里匹配pattern的字符串進(jìn)行全局替換,將替換后的行輸出stdout
p 將匹配行的內(nèi)容替換后輸出stdout
w file 將模式空間內(nèi)容寫到文件file中
替換命令s應(yīng)用于與[address]匹配的行。如果沒有指定行,那么就應(yīng)用于與pattern匹配的所有行。
在repalcement里可以利用&符號(hào),表示在替換字符串中引用pattern整個(gè)匹配內(nèi)容,如:
s/See Section [1-9][0-9]*".[1-9][0-9]*/(&)/ #給匹配的字符串添加小括號(hào)()
sed的控制流函數(shù):
!(非匹配)
[address]!command #在不匹配的行,執(zhí)行sed命令
或
[address1],[address2]!command
非命令導(dǎo)致(寫在同一行上的)下一個(gè)命令,應(yīng)用到所有的且只能是未被地址部分選擇到那些輸入行上。
/^$/!d
#刪除不是空行的所有行
{(命令集)
組合命令‘{’導(dǎo)致下一組命令作為一個(gè)塊而被應(yīng)用(或不應(yīng)用)到組合命令的地址所選擇的輸入行上。在組合控制下的的命令中的第一個(gè)命令可以出現(xiàn)在與‘{’相同的一行或下一行上。
組合的命令由自己獨(dú)立在一行之上的相匹配的‘}’終止。
組合可以嵌套。
:label(標(biāo)簽)
標(biāo)簽是任意不多于7個(gè)字符的序列。標(biāo)簽本身占據(jù)一行并以冒號(hào)開始:,如:
:mylabel
標(biāo)簽將被分支b和測試t命令調(diào)用,改變sed控制流。
b mylabel
注意不要在標(biāo)簽后插入空格
b(分支)
branch命令用于腳本將控制權(quán)轉(zhuǎn)移別處。
[address]b <label>
label是可選的,如果沒有給出label,sed對該行的控制流就會(huì)自動(dòng)轉(zhuǎn)移到結(jié)尾處。如果有l(wèi)abel就繼續(xù)執(zhí)行標(biāo)簽后的行。
例子:
/^".ES/,/^".EE/b
s/^"/''/
s/^$/''/
...
s/@DQ@/"/g
:top
command1
commnd2
/pattern/b top
command3
#模式pattern不匹配時(shí),sed執(zhí)行command1,command2,command3
#模式pattern匹配時(shí),控制流會(huì)跳轉(zhuǎn)到標(biāo)簽top處,sed執(zhí)行command1,command2,command1,command2,command3
command1
/pattern/b end
command2
:end
command3
#模式pattern不匹配時(shí),sed執(zhí)行command1,command2,command3
#模式pattern匹配時(shí),sed執(zhí)行command1,command3
t(測試是否成功替換)
test命令用于判斷當(dāng)前匹配的地址上是否進(jìn)行了成功替換?成功替換sed的控制流就轉(zhuǎn)到標(biāo)簽。
[address]t <label>
label是可選的,如果沒有給出label,sed對該行的控制流就會(huì)自動(dòng)轉(zhuǎn)移到結(jié)尾處。如果有l(wèi)abel就繼續(xù)
例子:
/".Rh 0/{
s/""(.*")"/"2,"3/g
t break
s/""(.*")"/"1,"2/g
t break
...
break:
more commands
}
#若該行有替換,則直接跳到break標(biāo)簽處執(zhí)行下邊命令
匹配多行:
假設(shè)我們的目標(biāo)文件test內(nèi)容是這樣的:
file content
aabbcc<<<comment part 1
comment part 2>>>
ddeeff
現(xiàn)在需要把<<<...>>>這一段替換為“COMMENT”,那么sed語法應(yīng)當(dāng)是:
:begin
/<<</,/>>>/ {
/>>>/! {
$! {
N;
b begin
}
}
s/<<<.*>>>/COMMENT/;
}
上述語句存儲(chǔ)在test.sed中,那么執(zhí)行的方式和結(jié)果就是:
$ sed -f test.sed test
file content
aabbccCOMMENT
ddeeff
把正則直接寫到命令里面也可以,用“;”來分隔命令即可:
$ sed -e ":begin; /<<</,/>>>/ { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
file content
aabbccCOMMENT
ddeeff
注意右花括號(hào)之后也要加上分號(hào)“;”,如果再加上-i
參數(shù)就可以直接把改動(dòng)寫到原文件中去了。
怎么樣?看懂了么?我來詳細(xì)說明吧,看那個(gè)多行命令的test.sed文件的內(nèi)容:
-
首先花括號(hào){}代表命令塊的開始,類似c的語法,后面就不再說了。
-
:begin
,這是一個(gè)標(biāo)號(hào),man中叫做label,也就是跳轉(zhuǎn)標(biāo)記,供b和t命令用,本例中使用了b命令。 -
/<<</,/>>>/
,這是一個(gè)地址范圍(Addresses),后面 {}中的命令只對地址范圍之間的內(nèi)容使用。其中逗號(hào)前面的部分是開始地址,逗號(hào)后面是結(jié)束地址,都是正則表達(dá)式。由于sed是“流”式“行”處理,所以結(jié) 束地址是可以省略的,即如果地址的結(jié)束范圍不存在,那么將一直處理到文件結(jié)尾。本例中使用這個(gè)地址范圍主要是縮小處理的數(shù)據(jù)量,因?yàn)殡m然后面用N命令把對 一行的處理擴(kuò)展為了多行,但如果從文件開頭一直N擴(kuò)展到<<<出現(xiàn)為止,buffer中要處理的字符串可能會(huì)很長,影響效率。所以去掉 這個(gè)處理范圍也是能夠得到正確結(jié)果的,比如:$ sed -e ":begin; { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
or
$ sed -e "{:begin; />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
-
/>>>/!
,>>>
是要替換內(nèi)容的結(jié)束標(biāo)記,帶上!
就是說當(dāng)一行處理完畢之后,如果沒有發(fā)現(xiàn)結(jié)束標(biāo)記。。。 -
$!
,$
在正則中表示字符串結(jié)尾,在sed中代表文件的最后一行,本句和上一句結(jié)合起來的意思就是:如果在本行沒有發(fā)現(xiàn)結(jié)束標(biāo)記,并且當(dāng)前掃描過的行并不是文件的最后一行。 -
N;
,把下一行的內(nèi)容追加(append)到緩沖區(qū)(pattern)之后,在我們的例子中,在處理aabbcc<<<comment part 1
這一行的內(nèi)容時(shí),就會(huì)執(zhí)行到這里,然后把下一行的內(nèi)容comment part 2>>>
一起放入緩沖區(qū),相當(dāng)于“合并”成了一行(sed的緩沖區(qū)中默認(rèn)都只會(huì)包含一行的內(nèi)容)。 -
b begin
,由于仍然沒有找到結(jié)束標(biāo)記<<<
(注意上一條說的緩沖區(qū)還沒有被處理),所以在這里跳回到標(biāo)號(hào)begin,重新開始命令。如果開始和結(jié)束標(biāo)記之間間隔了多行,那么就會(huì)有多次跳轉(zhuǎn)發(fā)生。 -
s/<<<.*>>>/COMMENT/;
,終于,/>>>/!
不再匹配成功,也就是我們已經(jīng)找到了結(jié)束標(biāo)記,那么用s命令來進(jìn)行替換。如果開始和結(jié)束標(biāo)記在一行的話,就會(huì)越過上面那些復(fù)雜的處理,直接執(zhí)行到這里了。
http://www.fwolf.com/blog/post/346
http://hi.baidu.com/hellolinuxworld/blog/item/5e3aa7080e6350c63bc76309.html