sed篇總共分成6章:(簡書版)
在開始之前蒲犬,首先回顧上一篇的重點內(nèi)容:地址匹配昆著。上一篇中介紹過,地址可以指定0個,1個或者2個嘹吨。地址的形式可以為斜杠分隔的正則表達式(例如/test/)藤滥,行號(例如3,5)或者特殊符號(例如$)暖混。如果沒有指定地址战坤,說明sed應用的編輯命令是全局的;如果是1個地址福稳,編輯命令只是應用到匹配的那一行涎拉;如果是一對地址,編輯命令則應用到該地址對匹配的行范圍的圆。關(guān)于地址匹配的內(nèi)容具體可以看Sed命令地址匹配問題總結(jié)鼓拧。
書中說,對于sed編輯命令的語法有兩種約定略板,分別是
[address]command? ? ? ? ? ? ? # 第一種
[line-address]command? ? ? ? ? # 第二種
第一種[address]是指可以為任意地址包括地址對毁枯,第二種[line-address]是指只能為單個地址。文中指出叮称,例如i(后方插入命令)种玛、a(前方追加命令)以及=(打印行號命令)等都屬于第二種命令,但是實際上我在ArchLinux上測試瓤檐,指定地址對也沒有報錯赂韵。不過為了兼容性,建議按作者所說的做挠蛉。
以下是要介紹的全部基礎(chǔ)命令:
名稱命令語法說明
替換s[address]s/pattern/replacement/flags替換匹配的內(nèi)容
刪除d[address]d刪除匹配的行
插入i[line-address]i\
text在匹配行的前方插入文本
追加a[line-address]a\
text在匹配行的后方插入文本
行替換c[address]c\
text將匹配的行替換成文本text
打印行p[address]p打印在模式空間中的行
打印行號=[address]=打印當前行行號
打印行l(wèi)[address]l打印在模式空間中的行祭示,同時顯示控制字符
轉(zhuǎn)換字符y[address]y/SET1/SET2/將SET1中出現(xiàn)的字符替換成SET2中對應位置的字符
讀取下一行n[address]n將下一行的內(nèi)容讀取到模式空間
讀文件r[line-address]r file將指定的文件讀取到匹配行之后
寫文件w[address]w file將匹配地址的所有行輸出到指定的文件中
退出q[line-address]q讀取到匹配的行之后即退出
替換命令: s
替換命令的語法是:
[address]s/pattern/replacement/flags
其中[address]是指地址,pattern是替換命令的匹配表達式谴古,replacement則是對應的替換內(nèi)容质涛,flags是指替換的標志位稠歉,它可以包含以下一個或者多個值:
n: 一個數(shù)字(取值范圍1-512),表明僅替換前n個被pattern匹配的內(nèi)容汇陆;
g: 表示全局替換怒炸,替換所有被pattern匹配的內(nèi)容;
p: 僅當行被pattern匹配時毡代,打印模式空間的內(nèi)容阅羹;
w file:僅當行被pattern匹配時,將模式空間的內(nèi)容輸出到文件file中教寂;
如果flags為空捏鱼,則默認替換第一次匹配:
$ echo"column1 column2 column3 column4"|sed's/ /;/'column1;column2 column3 column4
如果flags中包含g,則表示全局匹配:
$ echo"column1 column2 column3 column4"|sed's/ /;/g'column1;column2;column3;column4
如果flags中明確指定替換第n次的匹配酪耕,例如n=2:
$ echo"column1 column2 column3 column4"|sed's/ /;/2'column1 column2;column3 column4
當替換命令的pattern與地址部分是一樣的時候导梆,比如/regexp/s/regexp/replacement/可以省略替換命令中的pattern部分,這在單個編輯命令的情況下沒多大用處因妇,但是在組合命令的場景下還是能省不少功夫的问潭,例如下面是摘自文中的一個段落:
The substitute command is applied to the lines matching the address. If no
address is specified, it is applied to all lines that match the pattern, a
regular expression. If a regular expression is supplied as an address, and no
pattern is specified, the substitute command matches what is matched by the
address.? This can be useful when the substitute command is one of multiple
commands applied at the same address. For an example, see the section "Checking
Out Reference Pages" later in this chapter.
現(xiàn)在要在substitute command后面增加("s"),同時在被修改的行前面增加+號婚被,以下是使用的sed命令:
$ sed'/substitute command/{s//&("s")/;s/^/+ /}'paragraph.txt
這里我們用到了組合命令,并且地址匹配的部分和第一個替換命令的匹配部分是一樣的梳虽,所以后者我們省略了址芯,在replacement部分用到了&這個元字符,它代表之前匹配的內(nèi)容窜觉,這點我們在后面介紹谷炸。執(zhí)行后的結(jié)果為:
+ The substitute command("s") is applied to the lines matching the address. If no
address is specified, it is applied to all lines that match the pattern, a
regular expression. If a regular expression is supplied as an address, and no
+ pattern is specified, the substitute command("s") matches what is matched by the
+ address.? This can be useful when the substitute command("s") is one of multiple
commands applied at the same address. For an example, see the section "Checking
Out Reference Pages" later in this chapter.
替換命令的一個技巧是中間的分隔符是可以更改的(這個技巧我們在簡潔的Bash編程技巧續(xù)篇 - 5. 你知道sed的這個特性嗎?中也曾經(jīng)介紹過)禀挫,這個技巧在有些地方非常有用旬陡,比如路徑替換,下面是采用默認的分隔符和使用感嘆號作為分隔符的對比:
$ find/usr/local-maxdepth2-type d|sed's/\/usr\/local\/man/\/usr\/share\/man/'$ find/usr/local-maxdepth2-type d|sed's!/usr/local/man!/usr/share/man!'
替換命令中還有一個很重要的部分——replacement(替換內(nèi)容)语婴,即將匹配的部分替換成replacement描孟。在replacemnt部分中也有幾個特殊的元字符,它們分別是:
&: 被pattern匹配的內(nèi)容砰左;
\num: 被pattern匹配的第num個分組(正則表達式中的概念匿醒,\(..\)括起來的部分稱為分組;
\: 轉(zhuǎn)義符號缠导,用來轉(zhuǎn)義&廉羔,\, 回車等符號
&元字符我們已經(jīng)在上面的例子中介紹過,這里舉個例子介紹下\num的用法僻造。在Linux系統(tǒng)中憋他,默認都開了幾個tty可以讓你切換(ctrl+alt+1, ctrl+alt+2 ...)孩饼,例如CentOS 6.0+的系統(tǒng)默認是6個:
[root@localhost~]#grep-B1ACTIVE_CONSOLES/etc/sysconfig/init# What ttys should gettys be started on?ACTIVE_CONSOLES=/dev/tty[1-6]
可以通過修改上面的配置來減少開機啟動的時候創(chuàng)建的tty個數(shù),比如我們只想要2個:
[root@localhost~]#sed-r-i's!(ACTIVE_CONSOLES=/dev/tty\[1-)6]!\12]!'/etc/sysconfig/init
ACTIVE_CONSOLES=/dev/tty[1-2]
其中-i參數(shù)表示直接修改原文件竹挡,-r參數(shù)是指使用擴展的正則表達式(ERE)镀娶,擴展的正則表達式中分組的括號不需要用反斜杠轉(zhuǎn)義"(ACTIVE_CONSOLES=/dev/tty\[1-)",這里[是有特殊含義的(表示字符組)此迅,所以需要轉(zhuǎn)義汽畴。在替換的內(nèi)容中使用\1來引用這個匹配的分組內(nèi)容,1代表分組的編號耸序,表示第一個分組忍些。
刪除命令: d
刪除命令的語法是:
[address]d
刪除命令可以用于刪除多行內(nèi)容,例如1,3d會刪除1到3行坎怪。刪除命令會將模式空間中的內(nèi)容全部刪除罢坝,并且導致后續(xù)命令不會執(zhí)行并且讀入新行,因為當前模式空間的內(nèi)容已經(jīng)為空搅窿。我們可以試試:
$ sed'2,${d;=}'listJohnDaggett,341KingRoad,PlymouthMA
以上命令嘗試在刪除第2行到最后一行之后嘁酿,打印當前行號(=),但是事實上并沒有執(zhí)行該命令男应。
插入行/追加行/替換行命令: i/a/c
這三個命令的語法如下所示:
# Append 追加
[line-address]a\
text
# Insert 插入
line-address]i\
text
# Change 行替換
[address]c\
text
以上三個命令闹司,行替換命令(c)允許地址為多個地址,其余兩個都只允許單個地址(注:在ArchLinux上測試表明沐飘,追加和插入命令都允許多個地址游桩,sed版本為GNU sed version 4.2.1)
追加命令是指在匹配的行后面插入文本text;相反地耐朴,插入命令是指匹配的行前面插入文本text借卧;最后,行替換命令會將匹配的行替換成文本text筛峭。文本text并沒有被添加到模式空間铐刘,而是直接輸出到屏幕,因此后續(xù)的命令也不會應用到添加的文本上影晓。注意镰吵,即使使用-n參數(shù)也無法抑制添加的文本的輸出。
我們用實際的例子來簡單介紹下這三個命令的用法俯艰,依然用最初的文本list:
$ cat listJohnDaggett,341KingRoad,PlymouthMAAliceFord,22EastBroadway,RichmondVAOrvilleThomas,11345OakBridgeRoad,TulsaOKTerryKalkas,402LansRoad,BeaverFallsPAEricAdams,20PostRoad,SudburyMAHubertSims,328ABrookRoad,RoanokeVAAmyWilde,334BayshorePkwy,MountainViewCASalCarpenter,736thStreet,BostonMA
現(xiàn)在捡遍,我們要在第2行后面添加'------':
$ sed'2a\
--------------------------------------
'listJohnDaggett,341KingRoad,PlymouthMAAliceFord,22EastBroadway,RichmondVA--------------------------------------OrvilleThomas,11345OakBridgeRoad,TulsaOKTerryKalkas,402LansRoad,BeaverFallsPAEricAdams,20PostRoad,SudburyMAHubertSims,328ABrookRoad,RoanokeVAAmyWilde,334BayshorePkwy,MountainViewCASalCarpenter,736thStreet,BostonMA
或者可以在第3行之前插入:
$ sed'3i\
--------------------------------------
'listJohnDaggett,341KingRoad,PlymouthMAAliceFord,22EastBroadway,RichmondVA--------------------------------------OrvilleThomas,11345OakBridgeRoad,TulsaOKTerryKalkas,402LansRoad,BeaverFallsPAEricAdams,20PostRoad,SudburyMAHubertSims,328ABrookRoad,RoanokeVAAmyWilde,334BayshorePkwy,MountainViewCASalCarpenter,736thStreet,BostonMA
我們來測試下文本是否確實沒有添加到模式空間,因為模式空間中的內(nèi)容默認是會打印到屏幕的:
$ sed-n'2a\
--------------------------------------
'list--------------------------------------
通過-n參數(shù)來抑制輸出后發(fā)現(xiàn)插入的內(nèi)容依然被輸出竹握,所以可以判定插入的內(nèi)容沒有被添加到模式空間画株。
使用行替換命令將第2行到最后一行的內(nèi)容全部替換成'----':
$ sed'2,$c\
--------------------------------------
'listJohnDaggett,341KingRoad,PlymouthMA--------------------------------------
打印命令: p/l/=
這里純粹的打印命令應該是指p,但是因為后兩者(l和=)和p差不多,并且相對都比較簡單谓传,所以這里放到一起介紹蜈项。
這三個命令的語法是:
[address]p
[address]=
[address]l
p命令用于打印模式空間的內(nèi)容,例如打印list文件的第一行:
$ sed-n'1p'listJohnDaggett,341KingRoad,PlymouthMA
l命令類似p命令续挟,不過會顯示控制字符紧卒,這個命令和vim的list命令相似,例如:
$ echo"column1 column2 column3^M"|sed-n'l'column1\tcolumn2\tcolumn3\r$
=命令顯示當前行行號诗祸,例如:
$ sed'='list1JohnDaggett,341KingRoad,PlymouthMA2AliceFord,22EastBroadway,RichmondVA3OrvilleThomas,11345OakBridgeRoad,TulsaOK4TerryKalkas,402LansRoad,BeaverFallsPA5EricAdams,20PostRoad,SudburyMA6HubertSims,328ABrookRoad,RoanokeVA7AmyWilde,334BayshorePkwy,MountainViewCA8SalCarpenter,736thStreet,BostonMA
轉(zhuǎn)換命令: y
轉(zhuǎn)換命令的語法是:
[address]y/SET1/SET2/
它的作用是在匹配的行上跑芳,將SET1中出現(xiàn)的字符替換成SET2中對應位置的字符,例如1,3y/abc/xyz/會將1到3行中出現(xiàn)的a替換成x直颅,b替換成y博个,c替換成z。是不是覺得這個功能很熟悉功偿,其實這一點和tr命令是一樣的盆佣。可以通過y命令將小寫字符替換成大寫字符械荷,不過命令比較長:
$ echo"hello, world"|sed'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'HELLO,WORLD
使用tr命令來轉(zhuǎn)換成大寫:
$ echo"hello, world"|tr a-z A-Z
HELLO,WORLD
取下一行命令: n
取下一行命令的語法為:
[address]n
n命令為將下一行的內(nèi)容提前讀入共耍,并且將之前讀入的行(在模式空間中的行)輸出到屏幕,然后后續(xù)的命令會應用到新讀入的行上吨瞎。因此n命令也會同d命令一樣改變sed的控制流程痹兜。
書中給出了一個例子來介紹n的用法,假設(shè)有這么一個文本:
$ cat text.H1"On Egypt"Napoleon,pointing to thePyramids,said to his troops:"Soldiers, forty centuries have their eyes upon you."
現(xiàn)在要將.H1后面的空行刪除:
$ sed'/.H1/{n;/^$/d}'text.H1"On Egypt"Napoleon,pointing to thePyramids,said to his troops:"Soldiers, forty centuries have their eyes upon you."
讀寫文件命令: r/w
讀寫文件命令的語法是:
[line-address]r file
[address]w file
讀命令將指定的文件讀取到匹配行之后颤诀,并且輸出到屏幕佃蚜,這點類似追加命令(a)。我們以書中的例子來講解讀文件命令着绊。假設(shè)有一個文件text:
$ cat textForservice,contact any of the following companies:[Company-list]Thankyou.
同時我們有一個包含公司名稱列表的文件company.list:
$ cat company.listAlliedMayflowerUnited
現(xiàn)在我們要將company.list的內(nèi)容讀取到[Company-list]之后:
$ sed'/^\[Company-list]/r company.list'textForservice,contact any of the following companies:[Company-list]AlliedMayflowerUnitedThankyou.
更好的處理應當是用公司名稱命令替換[Company-list],因此我們還需要刪除[Company-list]這一行:
$ sed'/^\[Company-list]/r company.list;/^\[Company-list]/d;'textForservice,contact any of the following companies:[Company-list]Thankyou.
但是結(jié)果我們非但沒有刪除[Company-list]熟尉,而且company.list的內(nèi)容也不見了归露?這是怎么回事呢?
下面是我猜測的過程斤儿,讀文件的命令會將r空格后面的所有內(nèi)容都當成文件名剧包,即company.list;/^\[Company-list]/d;,然后讀取命令的時候發(fā)現(xiàn)該文件不存在往果,但是sed命令讀取不存在的文件是不會報錯的疆液。所以什么事都沒干成。
我們用-e選項將兩個命令分開就正常了:
$ sed-e'/^\[Company-list]/r company.list'-e'/^\[Company-list]/d;'textForservice,contact any of the following companies:AlliedMayflowerUnitedThankyou.
寫命令將匹配地址的所有行輸出到指定的文件中陕贮。假設(shè)有一個文件內(nèi)容如下堕油,前半部分是人名,后半部分是區(qū)域名稱:
$ cat textAdams,HenriettaNortheastBanks,FredaSouthDennis,JimMidwestGarvey,BillNortheastJeffries,JaneWestMadison,SylviaMidwestSommes,TomSouth
現(xiàn)在我們要將不同區(qū)域的人名字寫到不同的文件中:
$ sed'/Northeast$/w region.northeast
> /South$/w region.south
> /Midwest$/w region.midwest
> /West$/w region.west'textAdams,HenriettaNortheastBanks,FredaSouthDennis,JimMidwestGarvey,BillNortheastJeffries,JaneWestMadison,SylviaMidwestSommes,TomSouth
查看輸出的文件:
$ cat region.region.midwest? ? region.northeast? region.south? ? ? region.west
$ cat region.midwestDennis,JimMidwestMadison,SylviaMidwest
我們也可以試試將所有的w命令放到一起用分號分隔,發(fā)現(xiàn)會出下面的錯誤掉缺,它把w空格后面的部分當作文件名卜录,這樣就驗證了上面的猜測:
$ sed'/Northeast$/w region.northeast;/south$/w region.south;'text
sed:couldn't open file region.northeast;/south$/w region.south;: No such file or directory
退出命令: q
退出命令的語法是
[line-address]q
當sed讀取到匹配的行之后即退出,不會再讀入新的行眶明,并且將當前模式空間的內(nèi)容輸出到屏幕艰毒。例如打印前3行內(nèi)容:
$ sed'3q'listJohnDaggett,341KingRoad,PlymouthMAAliceFord,22EastBroadway,RichmondVAOrvilleThomas,11345OakBridgeRoad,TulsaOK
打印前3行也可以用p命令:
$ sed-n'3p'listJohnDaggett,341KingRoad,PlymouthMAAliceFord,22EastBroadway,RichmondVAOrvilleThomas,11345OakBridgeRoad,TulsaOK
但是對于大文件來說,前者比后者效率更高搜囱,因為前者讀取到第N行之后就退出了丑瞧。后者雖然打印了前N行,但是后續(xù)的行還是要繼續(xù)讀入蜀肘,只不會不作處理绊汹。
到此為止,sed基礎(chǔ)命令的部分就介紹完了幌缝。下面一篇的內(nèi)容會在最近幾天更新上來灸促,主要會介紹sed高級命令。不過一般情況下涵卵,會使用基礎(chǔ)命令已經(jīng)差不多了浴栽,高級命令不一定需要去了解。
下面是我整理的一份思維導圖(附.xmind文件下載地址):
轉(zhuǎn)自:團子的小窩, 本文固定鏈接:Sed and awk 筆記之 sed 篇:基礎(chǔ)命令