非交互式替換命令sed

1.將 "tiger" 修改爲 "wolf":

 

$ echo The tiger cubs will meet on Tuesday after school | sed 's/tiger/wolf/'

  The wolf cubs will meet on Tuesday after school

 

2.如果需要對同一文件或行作多次修改,可以有三種方法來實現它。

第一種是使用 "-e" 選項,它通知程序使用了多條編輯命令。例如:

 

$ echo The tiger cubs will meet on Tuesday after school | sed -e 's/tiger/wolf/' -e 's/after/before/'
The wolf cubs will meet on Tuesday before school
第二種是使用用分號來分隔命令: 

 

$ echo The tiger cubs will meet on Tuesday after school | sed '
s/tiger/wolf/; s/after/before/'
The wolf cubs will meet on Tuesday before school 
注意分號必須是緊跟斜線之後的下一個字符。如果兩者之間有一個空格,操作將不能成功完成,並返回一條錯誤消息。要注意的一個
關鍵問題是,兩個撇號 (' ') 之間的全部內容都被解釋爲 sed 命令。直到您輸入了第二個撇號,讀入這些命令的 shell 程序纔會認爲
您完成了輸入。這意味着可以在多行上輸入命令—同時 Linux 將提示符從 PS1 變爲一個延續提示符(通常爲 ">")—直到輸入了第
二個撇號。一旦輸入了第二個撇號,並且按下了 Enter 鍵,則處理就進行併產生相同的結果,如下所示: 

$ echo The tiger cubs will meet on Tuesday after school | sed '
> s/tiger/wolf/
> s/after/before/'
The wolf cubs will meet on Tuesday before school
3.全局替換修改 
讓我們開始一次看似簡單的編輯。假定在要修改的消息中出現了多次要修改的項目。默認方式下,結果可能和預期的有所不同,如下所示: 

$ echo The tiger cubs will meet this Tuesday at the same time as the meeting last Tuesday | sed 's/Tuesday/Thursday/'
The tiger cubs will meet this Thursday at the same time as the meeting last Tuesday
與將出現的每個 "Tuesday" 修改爲 "Thursday" 相反,sed 編輯器在找到一個要修改的項目並作了修改之後繼續處理下一行,而不讀整行。
sed 命令功能大體上類似於替換命令,這意味着它們都處理每一行中出現的第一個選定序列。爲了替換出現的每一個項目,在同一行中出現多
個要替換的項目的情況下,您必須指定在全局進行該操作: 

$ echo The tiger cubs will meet this Tuesday at the same time as the meeting last Tuesday | sed 's/Tuesday/Thursday/g'
The tiger cubs will meet this Thursday at the same time as the meeting last Thursday
4.sed 還可以用來修改記錄字段分隔符。例如,以下命令將把所有的 tab 修改爲空格: 

 

sed 's/	/ /g' 

 

其中,第一組斜線之間的項目是一個 tab,而第二組斜線之間的項目是一個空格。

5.有時,您不想修改在一個文件中出現的所有指定項目。有時,您只想在滿足某些條件時才作修改—例如,在與其它一些數據匹配之後才作修

改。爲了說明這一點,請考慮以下文本文件:


$ cat sample_one
one     1
two     1
three   1
one     1
two     1
two     1
three   1
$

假定希望用 "2" 來替換 "1",但僅在單詞 "two" 之後才作替換,而不是每一行的所有位置。通過指定在給出替換命令之前必須存在一次匹配,

可以實現這一點:


$ sed '/two/ s/1/2/' sample_one
one     1
two     2
three   1
one     1
two     2
two     2
three   1
$

現在,使其更加準確:


$ sed '
> /two/ s/1/2/
> /three/ s/1/3/' sample_one
one     1
two     2
three   3
one     1
two     2
two     2
three   3
$

請再次記住唯一改變了的是顯示。如果您查看源文件,您將發現它始終保持不變。您必須將輸出保存至另一個文件,以實現永久保存。值得重

復的是,不對源文件作修改實際是禍中有福—它讓您能夠對文件進行試驗而不會造成任何實際的損害,直到讓正確命令以您預期和希望的方式

進行工作。

以下命令將修改後的輸出保存至一個新的文件:


$ sed '
> /two/ s/1/2/
> /three/ s/1/3/' sample_one > sample_two

該輸出文件將所有修改合併在其中,並且這些修改通常將在屏幕上顯示。現在可以用 head、cat 或任意其它類似的實用工具來進行查看。

 

6. 腳本文件

sed 工具允許您創建一個腳本文件,其中包含從該文件而不是在命令行進行處理的命令,並且 sed 工具通過 "-f" 選項來引用。通過創建一個腳本文件,您能夠一次又一次地重複運行相同的操作,並指定比每次希望從命令行進行處理的操作詳細得多的操作。

考慮以下腳本文件:


$ cat sedlist
/two/ s/1/2/
/three/ s/1/3/

現在可以在數據文件上使用腳本文件,獲得和我們之前看到的相同的結果:


$ sed -f sedlist sample_one
one     1
two     2
three   3
one     1
two     2
two     2
three   3
$

注意當調用 "-f" 選項時,在源文件內或命令行中不使用撇號。腳本文件,也稱爲源文件,對於想重複多次的操作和從命令行運行可能出錯的

複雜命令很有價值。編輯源文件並修改一個字符比在命令行中重新輸入一條多行的項目要容易得多。

 

7.限制行

編輯器默認查看輸入到流編輯器中的每一行,且默認在輸入到流編輯器中的每一行上進行編輯。這可以通過在發出命令之前指定約束條件來進行修改。例如,只在此示例文件的輸出的第 5 和第 6 行中用 "2" 來替換 "1",命令將爲:


$ sed '5,6 s/1/2/' sample_one
one     1
two     1
three   1
one     1
two     2
two     2
three   1
$

在這種情況下,因爲要修改的行是專門指定的,所以不需要替換命令。因此,您可以靈活地根據匹配準則(可以是行號或一種匹配模式)來選

擇要修改哪些行(從根本上限制修改)。

 

8.禁止顯示

sed 默認將來自源文件的每一行顯示到屏幕上(或重定向到一個文件中),而無論該行是否受到編輯操作的影響,"-n" 參數覆蓋了這一操作。"-n" 覆蓋了所有的顯示,並且不顯示任何一行,而無論它們是否被編輯操作修改。例如:


$ sed -n -f sedlist sample_one
$

$ sed -n -f sedlist sample_one > sample_two
$ cat sample_two
$

在第一個示例中,屏幕上不顯示任何東西。在第二個示例中,不修改任何東西,因此不將任何東西寫到新的文件中—它最後是空的。這不是否定了編輯的全部目的嗎?爲什麼這是有用的?它是有用的僅因爲 "-n" 選項能夠被一條顯示命令 (-p) 覆蓋。爲了說明這一點,假定現在像下面這樣對腳本文件進行了修改:


$ cat sedlist
/two/ s/1/2/p
/three/ s/1/3/p
$

然後下面是運行它的結果:


$ sed -n -f sedlist sample_one
two     2
three   3
two     2
two     2
three   3
$

保持不變的行全部不被顯示。只有受到編輯操作影響的行被顯示了。在這種方式下,可以僅取出這些行,進行修改,然後把它們放到一個單獨的文件中:


$ sed -n -f sedlist sample_one > sample_two
$

$ cat sample_two
two     2
three   3
two     2
two     2
three   3
$

利用它的另一種方法是隻顯示一定數量的行。例如,只顯示 2-6 行,同時不做其它的編輯修改:


$ sed -n '2,6p' sample_one
two     1
three   1
one     1
two     1
two     1
$

其它所有的行被忽略,只有 2-6 行作爲輸出顯示。這是一項出色的功能,其它任何工具都不能容易地實現。Head 將顯示一個文件的頂部,而 tail 將顯示一個文件的底部,但 sed 允許從任意位置取出想要的任意內容。

 

9.刪除行

用一個值替換另一個值遠非流編輯器可以執行的唯一功能。它還具有許多的潛在功能,在我看來第二種最常用的功能是刪除。刪除與替換的工作方式相同,只是它刪除指定的行(如果您想要刪除一個單詞而不是一行,不要考慮刪除,而應考慮用空的內容來替換它—s/cat//)。

該命令的語法是:


'{what to find} d'

從 sample_one 文件中刪除包含 "two" 的所有行:


$ sed '/two/ d' sample_one
one     1
three   1
one     1
three   1
$

從顯示屏中刪除前三行,而不管它們的內容是什麼:


$ sed '1,3 d' sample_one
one     1
two     1
two     1
three   1
$

只顯示剩下的行,前三行不在顯示屏中出現。對於流編輯器,一般當它們涉及到全局表達式時,特別是應用於刪除操作時,有幾點要記住:


上三角號 (^) 表示一行的開始,因此,如果 "two" 是該行的頭三個字符,則


sed '/^two/ d' sample_one

將只刪除該行。

美元符號 ($) 代表文件的結尾,或一行的結尾,因此,如果 "two" 是該行的最後三個字符,則


sed '/two$/ d' sample_one

將只刪除該行。


將這兩者結合在一起的結果:


sed '/^$/ d' {filename}

刪除文件中的所有空白行。例如,以下命令將 "1" 替換爲 "2",以及將 "1" 替換爲 "3",並刪除文件中所有尾隨的空行:


$ sed '/two/ s/1/2/; /three/ s/1/3/; /^$/ d' sample_one
one     1
two     1
three   1
one     1
two     2
two     2
three   1
$

其通常的用途是刪除一個標題。以下命令將刪除文件中所有的行,從第一行直到第一個空行:


sed '1,/^$/ d' {filename}


10.添加和插入文本

可以結合使用 sed 和 "a" 選項將文本添加到一個文件的末尾。實現方法如下:


$ sed '$a/
> This is where we stop/
> the test' sample_one
one     1
two     1
three   1
one     1
two     1
two     1
three   1
This is where we stop
the test
$

在該命令中,美元符號 ($) 表示文本將被添加到文件的末尾。反斜線 (/) 是必需的,它表示將插入一個回車符。如果它們被遺漏了,則將導致一個錯誤,顯示該命令是錯亂的;在任何要輸入回車的地方您必須使用反斜線。

要將這些行添加到第 4 和第 5 個位置而不是末尾,則命令變爲:


$ sed '3a/
> This is where we stop/
> the test' sample_one
one     1
two     1
three   1
This is where we stop
the test
one     1
two     1
two     1
three   1
$

這將文本添加到第 3 行之後。和幾乎所有的編輯器一樣,您可以選擇插入而不是添加(如果您希望這樣的話)。這兩者的區別是添加跟在指定的行之後,而插入從指定的行開始。當用插入來代替添加時,只需用 "i" 來代替 "a",如下所示:


$ sed '3i/
> This is where we stop/
> the test' sample_one
one     1
two     1
This is where we stop
the test
three   1
one     1
two     1
two     1
three   1
$

新的文本出現在輸出的中間位置,而處理通常在指定的操作執行以後繼續進行。

11.讀寫文件

重定向輸出的功能已經演示過了,但需要指出的是,在編輯命令運行期間可以同步地讀入和寫出文件。例如,執行替換,並將 1-3 行寫到名稱爲 sample_three 的文件中:


$ sed '
> /two/ s/1/2/
> /three/ s/1/3/
> 1,3 w sample_three' sample_one
one     1
two     2
three   3
one     1
two     2
two     2
three   3
$

$ cat sample_three
one     1
two     2
three   3
$

由於爲 w (write) 命令指定了 "1,3",所以只有指定的行被寫到了新文件中。無論被寫的是哪些行,所有的行都在默認輸出中顯示。

修改命令

除了替換項目之外,還可以將行從一個值修改爲另一個值。要記住的是,替換是對字符逐個進行,而修改功能與刪除類似,它影響整行:


$ sed '/two/ c/
> We are no longer using two' sample_one
one     1
We are no longer using two
three   1
one     1
We are no longer using two
We are no longer using two
three   1
$

修改命令與替換的工作方式很相似,但在範圍上要更大些—將一個項目完全替換爲另一個項目,而無論字符內容或上下文。誇張一點講,

當使用替換時,只有字符 "1" 被字符 "2" 替換,而當使用修改時,原來的整行將被修改。在兩種情況下,要尋找的匹配條件都僅爲 "two"。

修改全部但……

對於大多數 sed 命令,詳細說明各種功能要進行何種修改。利用感嘆號,可以在除指定位置之外的任何地方執行修改—與默認的操作完全相

反。

例如,要刪除包含單詞 "two" 的所有行,操作爲:


$ sed '/two/ d' sample_one
one     1
three   1
one     1
three   1
$

而要刪除除包含單詞 "two" 的行之外的所有行,則語法變爲:


$ sed '/two/ !d' sample_one
two     1
two     1
two     1
$

如果您有一個文件包含一系列項目,並且想對文件中的每個項目執行一個操作,那麼首先對那些項目進行一次智能掃描並考慮將要做什麼是

很重要的。爲了使事情變得更簡單,您可以將 sed 與任意迭代例程(for、while、until)結合來實現這一目的。

比如說,假定您有一個名爲 "animals" 的文件,其中包含以下項目:

pig
horse
elephant
cow
dog
cat

您希望運行以下例程:


#mcd.ksh
for I in $*
do
echo Old McDonald had a $I
echo E-I, E-I-O
done

結果將爲,每一行都顯示在 "Old McDonald has a" 的末尾。雖然對於這些項目的大部分這是正確的,但對於 "elephant" 項目,它有

語法錯誤,因爲結果應當爲 "an elephant" 而不是 "a elephant"。利用 sed,您可以在來自 shell 文件的輸出中檢查這種語法錯誤,並

通過首先創建一個命令文件來即時地更正它們:


#sublist
/ a a/ s/ a / an /
/ a e/ s/ a / an /
/a i/ s / a / an /
/a o/ s/ a / an /
/a u/ s/ a / an /

然後執行以下過程:


$ sh mcd.ksh 'cat animals' | sed -f sublist 

現在,在運行了 mcd 腳本之後,sed 將在輸出中搜索單個字母 a (空格,"a",空格)之後緊跟了一個元音的任意位置。如果這種位置存在,

它將把該序列修改爲空格,"an",空格。這樣就使問題更正後才顯示在屏幕上,並確保各處的編輯人員在晚上可以更容易地入睡。結果是:

Old McDonald had a pig
E-I, E-I-O
Old McDonald had a horse
E-I, E-I-O
Old McDonald had an elephant
E-I, E-I-O
Old McDonald had a cow
E-I, E-I-O
Old McDonald had a dog
E-I, E-I-O
Old McDonald had a cat
E-I, E-I-O

提前退出

sed 默認讀取整個文件,並只在到達末尾時才停止。不過,您可以使用退出命令提前停止處理。只能指定一條退出命令,而處理將一直持續直到

滿足調用退出命令的條件。

例如,僅在文件的前五行上執行替換,然後退出:


$ sed '
> /two/ s/1/2/
> /three/ s/1/3/
> 5q' sample_one
one     1
two     2
three   3
one     1
two     2
$

在退出命令之前的項目可以是一個行號(如上所示),或者一條查找/匹配命令:


$ sed '
> /two/ s/1/2/
> /three/ s/1/3/
> /three/q' sample_one
one     1
two     2
three   3
$

您還可以使用退出命令來查看超過一定標準數目的行,並增加比 head 中的功能更強的功能。例如,head 命令允許您指定您想要查看一個

文件的前多少行—默認數爲 10,但可以使用從 1 到 99 的任意一個數字。如果您想查看一個文件的前 110 行,您用 head 不能實現這一

目的,但用 sed 可以:


sed 110q filename

處理問題

當使用 sed 時,要記住的重要事項是它的工作方式。它的工作方式是:讀入一行,在該行上執行它已知要執行的所有任務,然後繼續處理下一

行。每一行都受給定的每一個編輯命令的影響。

如果您的操作順序沒有十分徹底地考慮清楚,那麼這可能會很麻煩。例如,假定您需要將所有的 "two" 項目修改爲 "three",然後將所有

的 "three" 修改爲 "four":


$ sed '
> /two/ s/two/three/
> /three/ s/three/four/' sample_one
one     1
four     1
four   1
one     1
four     1
four     1
four   1
$

最初讀取的 "two" 被修改爲 "three"。然後它滿足爲下一次編輯建立的準則,從而變爲 "four"。最終的結果不是想要的結果—現在除

了 "four" 沒有別的項目了,而本來應該有 "three" 和 "four"。

當執行這種操作時,您必須非常用心地注意指定操作的方式,並按某種順序來安排它們,使得操作之間不會互相影響。例如:


$ sed '
> /three/ s/three/four/
> /two/ s/two/three/' sample_one
one     1
three     1
four   1
one     1
three     1
three     1
four   1
$

這非常有效,因爲 "three" 值在 "two" 變成 "three" 之前得到修改。

標籤和註釋

可以在 sed 腳本文件中放置標籤,這樣一旦文件變得龐大,可以更容易地說明正在發生的事情。存在各種各樣與這些標籤相關的命令,

它們包括: 接下來的步驟

訪問並收藏 Linux 技術中心

閱讀 Dale Dougherty 和 Arnold Robbins 的著作 sed & awk, 2nd Edition (O'Reilly & Associates 出版社)。
 


: 冒號表示一個標籤名稱。例如:


:HERE

以冒號開始的標籤可以由 "b" 和 "t" 命令處理。


b {label} 充當 "goto" 語句的作用,將處理髮送至前面有一個冒號的標籤。例如,


b HERE

將處理髮送給行


:HERE

如果緊跟 b 之後沒有指定任何標籤,則處理轉至腳本文件的末尾。


t {label} 只要自上次輸入行或執行一次 "t" 命令以來進行了替換操作,就轉至該標籤。和 "b" 一樣,如果沒有給定標籤名,則處理轉至

腳本文件的末尾。


# 符號作爲一行的第一個字符將使整行被當作註釋處理。註釋行與標籤不同,不能使用 b 或 t 命令來轉到註釋行上。

進一步的研究
sed 實用工具是 Linux 管理員擁有的最強大和靈活的工具之一。雖然本文覆蓋了許多基礎知識,但對於這一具有豐富功能的工具僅是蜻蜓

點水。關於更多信息,最好的來源之一是 Dale Dougherty 和 Arnold Robbins 的著作 sed & awk,現在從 O'Reilly & Associates

出版社推出了其第二版(參加“接下來的步驟”)。該出版社還推出了一本可以隨身攜帶的袖珍參考。

 

 

 

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章