歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Unix知識 >> Unix基礎知識 >> Unix基礎教程(3)

Unix基礎教程(3)

日期:2017/2/25 10:12:34   编辑:Unix基礎知識

第3章全屏幕編輯程序vi

【例3-1】 將abc字符串替換為xyz。

:1,50s/abc/xyz/

將第1-50行的字符串abc換為xyz,如果同一行內有多個abc字符串,則只替換第一個。

:1,50s/abc/xyz/g

將第1-50行的字符串abc換為xyz,如果同一行內有多個abc字符串,則替換所有的abc字符串。

:s/abc/xyz/g

僅將當前行的字符串abc換為xyz,如果當前行中有多個abc字符串,則替換所有的abc字符串。

【例3-2】在編輯C語言源程序時,把一部分行右移/左移四列。

:50,80s/^/ /g

這樣,在50~80行的行首增加了四個空格,從效果上看,第50~80行右移4列。

:50,80s/^ //g

這樣,在50~80行的行首的四個空格被替換成空字符串,從效果上看,第50~80行左移4列(每行首部必須有四個空格)。

② 模式描述使用正則表達式

使用替換命令時應特別注意在描述模式時使用的是正則表達式,尤其是在編輯C語言源程序時,不要忘記在應該加轉義符時加上轉義符。下面的例子中的轉義符\是必不可少的。

【例3-3】注意vi替換命令中用於模式描述的正則表達式中的特殊字符。

(1) 將end.改為middle.。

:1,$s/end\./middle./g

指定范圍為從第一行到最後一行,就是在整個文件中替換。middle後邊的圓點前不需要加反斜線。這裡的middle.是替換字符串,不是正則表達式,圓點就沒有任何特殊含義,因此不能在它前邊加反斜線。

(2) 刪除每行尾部的一個字符。

:1,$s/.$//g

將Windows中的文本文件按照二進制格式拷貝到Unix系統中,由於兩種系統文本文件存儲格式上的差異,在UNIX看來每行尾部都多余一個ASCII碼為13的字符,在vi顯示的時候,每行尾部顯示一個^M,使用上述的命令,將行尾的一個字符替換為空字符串,就可以將行尾的^M消除。但使用:1,$s/\^M//g不能達到目的。

(3) 將a[i]*b[j]替換為x[k]*y[n]。

:1,$s/a\[i]\*b\[j]/x[k]*y[n]/g

將buf.length/1000替換為 buffer.size/1024。

:1,$s/buf\.length\/1000/buffer.size\/1024/g

在這裡模式和替換字符串中的斜線前加轉義符\,以區別於替換命令格式中所必須的斜線。

(4) 在編輯C語言程序的時候,將f[n]替換為f[i]。

使用下面的命令:

:1,$s/f[n]/f[i]/g

結果,會發現源程序中的f[n]未被替換,程序員會誤以為可能打字錯誤,重新鍵入命令,發現程序文件中的f[n]仍然未被替換。既然這個命令不能達到期望的結果,著急調試程序的程序員,會手工逐個找到f[n]一個個的改為f[i]。上述的替換命令失敗的原因是,正則表達式f[n]與字符串f[n]並不匹配,它只能與fn匹配。在一個較大的程序文件中,如果湊巧有個變量的名字叫fn,那麼,由於這段時間程序員把注意力都集中在他試圖修改的f[n],fn被悄悄地替換成了不期望的f[i]。如果編譯源程序時未發生任何錯誤,就會給原本正確的程序引入一個錯誤。正確的命令是:

:1,$s/f\[n]/f[i]/g

類似的,將當前行開始到文件尾的段落中所有的x*y替換為x+y,使用下面的命令:

:.,$s/x*y/x+y/g

結果是,源程序中的x*y被替換為x*x+y,而且,其它地方的y都被替換成了x+y。因為正則表達式x*y可以與字符串y匹配,星號可以是它左邊的單字符正則表達式的0次重復。正確的用法是:

:.,$s/x\*y/x+y/g

③ 替換字符串中的符號&

在替換字符串中特殊字符&,代表被模式所匹配的那部分。

【例3-4】替換字符串中&符的作用。

設文件當前只含有四行,每行為一個整數,內容為

5

2

10

18

執行下邊的命令

:1,$s/[0-9][0-9]*/192.168.24.& host&/

然後,文件內容變為

192.168.24.5 host5

192.168.24.2 host2

192.168.24.10 host10

192.168.24.18 host18

上述命令描述模式時使用[0-9][0-9]*,如果僅使用[0-9]*,那麼,是錯誤的。由於星號作用於它前邊的單字符正則表達式,可以是0次出現,所以[0-9]*可以與任意“空字符串”匹配。

&是C語言中常用的符號,所以要特別注意。將*pointer替換為&record的命令是:

:1,$s/\*pointer/\&record/g

③ 使用正則表達式的更靈活替換

這種替換方法,擴展了基本的正則表達式,增加\(和\),在左右圓括號前面綴以轉義符。在正則表達式中出現的圓括號,仍然代表它自身。在正則表達式中出現的\(和\)不影響匹配操作。

下邊的兩個正則表達式匹配相同的字符串。

[a-zA-Z_][a-zA-Z0-9_]*->number

\([a-zA-Z_][a-zA-Z0-9_]*\)->number

字符串ptr->number和Term370_blk->number都與上述兩個正則表達式匹配。使用\(和\)的目的不在於匹配操作,而是在於替換操作。對於能夠匹配的字符串來說,用\(和\)標注出來的一段,可以在替換字符串中使用。上例中,在替換字符串中使用\1,就代表了\(和\)標注出來的那段正則表達式所匹配的部分,上面給出的兩個字符串的例子中分別是ptr和Term3270_blk。如果正則表達式中有多段這樣標記出的部分,在替換字符串中分別使用\2,\3,……。

【例3-5】使用正則表達式中\(和\)實現更靈活的替換功能。

這種正則表達式替換在其它命令中和其它的非UNIX系統中也廣泛使用,Windows的Visual C++編輯器也支持此種替換。UNIX的expr命令,也是用這種方法從一個字符串中提取部分內容,參見6.7.2節的“字符串運算”部分。

(1) 下邊的命令完成了number到num的替換,但是這種替換僅限於在一個C語言指針引用之後的number,對於其它地方出現的number不進行替換。

:1,$s/\([a-zA-Z_][a-zA-Z0-9_]*\)->number/\1->num/g

(2) 將文件中的日期格式“月-日-年”改為“年.月.日”,比如:04-26-1997替換為1997.04.26,使用的命令為:

:1,$s/\([0-9][0-9]\)-\([0-9][0-9]\)-\([0-9][0-9]*\)/\3.\2.\1/g

(3) 替換字符串中可以使用特殊的\0代表被整個正則表達式匹配的部分,前面例3-4中的命令:

:1,$s/[0-9][0-9]*/192.168.24.& host&/

也可以等價的寫作下列的命令:

:1,$s/[0-9][0-9]*/192.168.24.\0 host\0/

Copyright © Linux教程網 All Rights Reserved