亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区
Chinaunix
標(biāo)題:
sed基礎(chǔ)概念
[打印本頁]
作者:
mmx384
時(shí)間:
2007-11-19 20:57
標(biāo)題:
sed基礎(chǔ)概念
這是一篇從CU SHELL版移過來的文章
這篇文章是我學(xué)習(xí)sed后的一點(diǎn)感受,我的實(shí)際工作用不上sed,學(xué)習(xí)它僅僅是不想讓花了我42RMB的《sed&awk》一直躺在書架上。我對(duì)
本版的帖子做過一次過濾,回復(fù)較多的帖子大概地瀏覽了一遍,搜集例子中的數(shù)據(jù)做練習(xí)。sed&awk講了一些sed的基礎(chǔ)概念,我感受最深的就是
行的概念了,所以我想說說我的一點(diǎn)理解,顯然淺顯,但正適合初學(xué)者(如我)閱讀。
環(huán)境{
GNU/Linux
bash 3.0
GNU sed 4.1.4
}
先看兩個(gè)例子:
對(duì)于如下sed命令,大家都知道d刪除的不是字符串“pattern”,而是包含字符串pattern的一整行
sed '/pattern/d' testfile
所以d命令的操作是基于行的。類似的,p命令也是基于行的,有這樣一個(gè)例子
echo "ABA,aaa" | sed -n '/^[A-Z]*[,][a-z]*/p'
echo "ABA,aaa" | sed -n '/^[A-Z]*[^,][a-z]*/p'
兩個(gè)命令的屏幕輸出完全一樣,令人迷惑為什么“看起來相反”的正則表達(dá)式匹配的結(jié)果卻一樣,其實(shí)"顯示結(jié)果一樣!=正則表達(dá)式匹配結(jié)果相同",換成如下命令試一試
echo "ABA,aaa" | grep --color '^[A-Z]*[,][a-z]*'
echo "ABA,aaa" | grep --color '^[A-Z]*[^,][a-z]*'
結(jié)果很顯然,sed中p命令是基于行的,把包含匹配的整個(gè)行輸出到屏幕。
(包括下面的每個(gè)例子,請(qǐng)動(dòng)手實(shí)際操作一下,觀察一下屏幕輸出與你的預(yù)想結(jié)果是否一致)
sed有一套編輯命令,都是基于行操作的,雖然功能不同,但是你用基本的sed概念去理解這些命令,將很快掌握sed。本文先介紹兩個(gè)sed的基礎(chǔ)概念,然后用這個(gè)基礎(chǔ)概念結(jié)合例子理解sed常用的編輯命令。
1.請(qǐng)永遠(yuǎn)記住這個(gè)規(guī)則:
[color="Red"]一次讀取一行
sed把輸入看成文本流。將一個(gè)文本文件當(dāng)成一串以'\n'分隔的有限長的字串。sed每次讀入一行(為當(dāng)前行),將其保存在內(nèi)存緩沖區(qū)(稱做模式空間),并將腳本中所有操作命令依次應(yīng)用于當(dāng)前行。(如果你讀過過UNIX入門一類的書籍,對(duì)文本流這個(gè)概念一定不會(huì)陌生,發(fā)揮你的想像,想像一下sed將一行一行的文本,看成是相連的串,用流來形容,非常貼切吧)
截取Xorg.conf中的一段文本做例子,體會(huì)一下“一次讀取一行”是怎么回事:
Section "InputDevice"
Identifier "Keyboard0"
Driver "kbd"
Option "XkbModel" "pc105"
Option "XkbLayout" "en_US,ru"
EndSection
#==================================================
Section "InputDevice"
Identifier "Mouse0"
Driver "mouse"
Option "Protocol" "auto"
Option "Device" "/dev/mouse"
Option "ZAxisMapping" "4 5"
# Option "Buttons" "5"
EndSection
執(zhí)行下面這個(gè)sed命令之后,Section和EndSection之間的行將被刪除,僅保留了中間一行
sed '/^Section/,/EndSection/d' testfile
嘗試把文本中最后一個(gè)EndSection刪除,再次執(zhí)行上面這個(gè)命令,跟你預(yù)想的結(jié)果一樣嗎?修改后的文本不匹配/^Section/,/^EndSection/,為什么還會(huì)將其刪除?
在這個(gè)例子中,sed并不把/^Section/,/^EndSection/之間的多個(gè)行一次讀入到內(nèi)存中,而僅僅是一次讀一行,將其復(fù)制到內(nèi)存中的某
個(gè)緩沖區(qū),sed將這個(gè)緩沖區(qū)叫做模式空間,模式空間存放的內(nèi)容叫做當(dāng)前行,然后在這個(gè)當(dāng)前行中搜索開始字符串Section,找到后執(zhí)行d刪除命令,繼
續(xù)讀取下一行,搜索結(jié)束字符串,如果沒有找到,sed會(huì)認(rèn)為當(dāng)前行是Section和EndSection之間的行將其刪除,而不管后面的行中是否包含
EndSection。如果后面沒有結(jié)束字符串,一直刪除到文件結(jié)束。
sed一次僅讀取一行,不可能預(yù)知后面是否含有結(jié)束字符串,對(duì)于處理這樣的例子,sed有一定的局限性。但是,一次處理一行的設(shè)計(jì)使sed簡潔而高效。
SHELL版常有處理大文件(幾百M(fèi)甚至上G)時(shí)的效率問題,我對(duì)自造的一個(gè)不斷重復(fù)內(nèi)容的100M測(cè)試文件進(jìn)行替換測(cè)試,sed雖然比不上awk,但速度還是可以接受的。有興趣可以自己試一下:
for ((i=0; i> /tmp/boot.log
done && \
time sed -n 's/kernel/KERNEL/g'
在我的機(jī)器上{lenovo3110:p41.7G}測(cè)試結(jié)果如下(我的樣本文件中7500行的boot.log有896行含有kernel,重復(fù)200次內(nèi)容后文件是112MB):
time sed -n 's/kernel/KERNEL/g'
real 0m3.292s
time sed -i 's/kernel/KERNEL/g'
real 0m16.741s
雖然僅測(cè)試一個(gè)替換,不是測(cè)試一個(gè)腳本,但從中或多或少可以感受一下sed的簡潔快速。
2. 規(guī)則1的附加規(guī)則:
sed對(duì)讀取的當(dāng)前行依次運(yùn)行整個(gè)腳本命令
腳本最后一個(gè)命令執(zhí)行完后sed輸出模式空間的內(nèi)容,并自動(dòng)讀取下一行再次從頭執(zhí)行腳本,如此不斷循環(huán)
這是一個(gè)簡單的腳本:
:labp
假設(shè)有一個(gè)文本內(nèi)容如下:
1 channel list:
2 http://www.sopcast.com/chlist.xml
3 A simple example of sp-sc command line.
4 ./sp-sc sop://broker.sopcast.com:3912/6098 3908 8908 > /dev/null &
5 Start to transfer channel 6098, 8908 with VLC or mplayer
6 by open the url: http://localhost:8908/tv.asf
對(duì)這個(gè)文本執(zhí)行命令:
sed -f script file
我們來看一下sed是如何執(zhí)行的
sed讀取第一行到模式空間,依次執(zhí)行腳本中的所有命令,p命令將當(dāng)前模式空間的內(nèi)容輸出到屏幕,然后冒號(hào)定義一個(gè)標(biāo)簽(這個(gè)標(biāo)簽后面沒有用到,只是幫助理解腳本而設(shè)),之后由于執(zhí)行完了所有的命令,sed默認(rèn)會(huì)輸出當(dāng)前模式空間的內(nèi)容。于是在屏幕上你將看到兩行
1 channel list:
1 channel list:
執(zhí)行完了腳本中所有的命令后,sed會(huì)自動(dòng)讀取一下行,再次循環(huán)整個(gè)腳本。如此不斷循環(huán),直到處理完文件的最后一行后結(jié)束退出sed。
猜測(cè)一下用下面的腳本處理后面的文本,結(jié)果會(huì)怎樣?
s/Unix/UNIX/g
s/UNIX/UNIX System/g
對(duì)下面的文本執(zhí)行命令: sed -f script file
A
beginners guide to the Unix and Linux operating system. Eight simple
tutorials which cover the basics of UNIX / Linux commands.
對(duì)輸出結(jié)果自已解釋一下吧。
3.
[color="Red"]n,d,N,t,T,b命令以不同的方式影響文本流
如果沒有if,for,while,可以想像一下C語言能夠做什么?總是讓腳本順序執(zhí)行,有很大一部分問題將不能解決,必須用某些命令控制文本流。
用上面的兩個(gè)基礎(chǔ)概念來理解這幾個(gè)命令
[color="Red"]1) n
cat -n /etc/profile > /tmp/file
sed -n 'p;n' /tmp/file
sed -n 'n;p' /tmp/file
這兩個(gè)例子非常奇妙地利用n命令打印奇數(shù)行和偶數(shù)行,簡單地分析一下:
p
n
sed
首先讀取輸入文件file中的第一行復(fù)制到模式空間,對(duì)模式空間的當(dāng)前行依次運(yùn)行腳本中的每一個(gè)命令,p命令將當(dāng)前行輸出到屏幕,然后n命令迫使sed讀
取下一行(第二行),之后由于腳本所有的命令已經(jīng)執(zhí)行完畢,sed會(huì)將當(dāng)前模式空間的內(nèi)容(此時(shí)即第二行)輸出到屏幕(-n抑制了這個(gè)操作),接著讀取第
三行到模式空間,并自頂向下運(yùn)行腳本命令,開始第二次循環(huán)。
在這里要注意兩次讀取操作:
1. n命令迫使sed讀取下一行到模式空間;
2. 腳本中所有的命令執(zhí)行完后{p;n},sed會(huì)自動(dòng)讀取下一行,并返回腳本頂端開始下一次循環(huán)。
跳過一些不想在其上執(zhí)行命令的行,這是n命令的拿手好戲。下面例子對(duì)/var/log/xorg.0.log執(zhí)行如下腳本,將對(duì)包含"(II)"的行不執(zhí)行替換操作:
/(II)/{
n
}
s/SIS/sis/g
[color="Red"]2) d
d命令也會(huì)迫使sed讀取下一行,不過與n命令有一個(gè)微妙的區(qū)別。
d命令刪除模式空間的內(nèi)容,命令執(zhí)行后模式空間沒有內(nèi)容,導(dǎo)致d命令后面的其它命令將不能作用于模式空間,迫使sed讀取下一行,并返回腳本頂部開始下一次循環(huán)。
我碰到過這樣一個(gè)問題:寫了一個(gè)1000行的C源程序,其中用到一個(gè)變量getnum,想將其替換為get_int_num,但是函數(shù)isyn(){...}內(nèi)的getnum保持不變。
我第一次想用n命令實(shí)現(xiàn):
/isyn()/,/^}/{
n
}
s/getnum/get_int_num/g
結(jié)果失敗了,具體的例子用一個(gè)簡短的數(shù)據(jù)來說明一下:
將下面這個(gè)六行數(shù)據(jù)中除A~S的行外,所有的小寫字母替換為*號(hào)
1 channel list:
2 http://www.sopcast.com/chlist.xml
3 A simple example of sp-sc command line.
4 ./sp-sc sop://broker.sopcast.com:3912/6098 3908 8908 > /dev/null &
5 Start to transfer channel 6098, 8908 with VLC or mplayer
6 by open the url: http://localhost:8908/tv.asf
即變成:
1 ******* ****:
2 ****://***.*******.***/******.***
3 A simple example of sp-sc command line.
4 ./sp-sc sop://broker.sopcast.com:3912/6098 3908 8908 > /dev/null &
5 Start to transfer channel 6098, 8908 with VLC or mplayer
6 ** **** *** ***: ****://*********:8908/**.***
腳本如下:
/A/,/S/{
n
}
s/[a-z]/*/g
當(dāng)sed讀取第三行到模式空間為當(dāng)前行時(shí),腳本搜索到了A并執(zhí)行n命令讀取第四行,此時(shí)sed并沒有返回腳本頂部重新執(zhí)行命令,而是繼續(xù)執(zhí)行n命令后的s命令,將替換操作作用于第四行。
當(dāng)我發(fā)現(xiàn)第四行作了替換后,嘗試多次使用n命令失敗,最后用p命令和d命令組合,變相地跳過了A~S行
/A/,/S/{
p
d
}
s/[a-z]/*/g
sed
讀取第三行到模式空間后,先輸出到屏幕后刪除,根據(jù)d命令的特性,被d刪除的模式空間沒有內(nèi)容,將不能對(duì)它進(jìn)行腳本后s/[a-z]/*/g的替換操作,
迫使sed讀取第四行并返回腳本頂部開始執(zhí)行,由于第四仍包含在/A/,/S/內(nèi),將再次執(zhí)行{p;d}操作,如此循環(huán)將/A/,/S/內(nèi)的行變相地跳過
而不作替換。
[color="Red"]3) N
N命令與n命令的區(qū)別是
n讀取下一行,并用讀取的行將當(dāng)前模式空間的內(nèi)容“擠”出去,而N命令讀取下一行后將讀取的行追加到模式空間,兩個(gè)行之間用一個(gè)'\n'分隔。這有點(diǎn)類似于>和>>重定向符
假如文件當(dāng)作一個(gè)模式空間的話,執(zhí)行下面的命令n次
echo "Hello,World." > file
文件內(nèi)將只有最后一次寫入到其中的Hello,World.而如果執(zhí)行的是下面的命令
echo "Hello,World." >> file
文件內(nèi)將有n行Hello,World。
回到那個(gè)輸出文件奇數(shù)/偶數(shù)行的例子,可以用下面的命令輸出奇數(shù)/偶數(shù)行:
(大寫的P命令輸出模式空間第一個(gè)'\n'前的內(nèi)容)
sed -n 'N;P' file
sed -n 'P;N' file
如果要輸出偶數(shù)行
sed -n '1!P;1!N' file
這個(gè)例子很好地說明了N命令是如何執(zhí)行的,并再一次證明了這個(gè)附加規(guī)則“腳本最后一個(gè)命令執(zhí)行完后sed輸出模式空間的內(nèi)容,并自動(dòng)讀取下一行再次從頭執(zhí)行腳本,如此不斷循環(huán)”
[color="Red"]4) t,T,b (下面僅舉幾個(gè)例子,解釋起來太費(fèi)勁了)
這三個(gè)都是跳轉(zhuǎn)命令。t和T是對(duì)s替換操作是否成功進(jìn)行測(cè)試,然后決定如何跳轉(zhuǎn),類似if語句;而b命令則無條件地跳轉(zhuǎn)。
返回上面的一個(gè)例子:
/A/,/S/{
p
d
}
s/[a-z]/*/g
可以將這個(gè)腳本修改為(不帶標(biāo)簽的b命令將跳轉(zhuǎn)到腳本的底部):
/A/,/S/{
b
}
s/[a-z]/*/g
請(qǐng)用上面的兩個(gè)基礎(chǔ)概念自行解釋一下運(yùn)行這個(gè)腳本的詳細(xì)過程
下面這個(gè)例子試圖將/A/,/S/之間的多個(gè)行合并為一行,但是沒有成功,你可以用前面的文本測(cè)試一下:
/A/,/S/{
:lab
$!N
s/\n//g
t lab
}
可以將其修改為這樣
/A/{
:lab
/S/b
$!N
s/\n//g
t lab
}
最后,用這個(gè)腳本可以刪除下面的變態(tài)C注釋
/\/\*/{
/\*\//s@/\*.*\*/@@ #刪除在同一行上的 /* ...... */
t #如果替換成功則轉(zhuǎn)到腳本底部,結(jié)束一次/*.....*/替換
s@/\*.*$@@ #不成功則繼續(xù)執(zhí)行:刪除/*到行尾(/*前面可能有代碼)
:lab
n
s@.*\*/@@ #搜索是否包含結(jié)束串*/將其替換
t #如果替換成功說明已經(jīng)刪除了/*...*/
s@^.*$@@ #不成功則將行替換為空:這里不能用d,d會(huì)跳出這個(gè)循環(huán)
b lab
}
測(cè)試用的C文本
#include
main()
{
/*需要整行刪除*/
printf("本句和注釋之間的空格不要去掉\n"); /*just a test
******需要整行刪除
/////需要整行刪除
需要整行刪除,后面空行不要?jiǎng)h除*/
printf("漢字不能被刪除\n");
/*test 注意前面空行不能刪除
*/ printf("test:前面的空格不要去掉\n");/*a
*/printf("test3\n");
return(0);
}
不夠完美,須要執(zhí)行兩次sed:
sed -f script test.c | sed -f script
不當(dāng)之處,尚請(qǐng)批評(píng)指正。感謝CU SHELL版的各位xdjm,讓我在這里學(xué)會(huì)了很多東西。
本文來自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):
http://blog.chinaunix.net/u/15571/showart_426229.html
歡迎光臨 Chinaunix (http://72891.cn/)
Powered by Discuz! X3.2