sed編輯器基礎

知識點掃盲

sed——流編輯器(stream editor),它在處理數據之前基於預先提供的一組規則來編輯數據流。
sed編輯器根據命令來處理數據流中的數據,這些命令可以來自命令行,也可以存儲到文件中。
sed編輯器處理數據流時,會執行以下操作:

  1. 一次從輸入中讀取一行數據;
  2. 根據預先提供的命令匹配數據;
  3. 按照命令修改流中的數據;
  4. 將新的數據輸出到STDOUT;

sed命令的格式:
sed options script file
options選項:

  • -e script: 在處理輸入時,將script中指定的命令添加到已有的命令中;
  • -f file:在處理輸入時,將file中指定的命令添加到已有的命令中;
  • -n : 不產生命令輸出,使用print命令完成打印輸出;

基礎命令

在命令行定義編輯器命令

$ echo "This is a test" | sed 's/test/real test/'
This is a real test
$

這個例子中使用了s命令,s命令會用指定分隔符使用第二個文本字符串替換第一個文本字符串。例子中使用real test 替換了 test
sed編輯器的強大之處在於結果會立即顯示出來。你可以同時對數據做出多處修改,但消耗的時間只夠一些交互式編輯器啓動而已。

$ cat sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$ sed 's/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.

可以很明顯的看到,sed命令幾乎瞬間就執行完並返回數據,在處理每行數據的同時,結果也顯示出來了。
這裏需要明確的是, sed並不會修改文件的數據,它只是將修改後的數據發送到STDOUT。

在命令行使用多個編輯命令

要在sed命令行上執行多個命令時,只要使用-e選項就可以了。

$ sed -e 's/brown/green/; s/dog/cat/' sedData1.txt
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.

執行的兩個命令都作用到每行數據上,命令之間必須用分號隔開,並且命令末尾和分號之間不能有空格
如果不想用分號,也可以使用bash shell中的次提示符分隔命令。

$ sed -e '
quote> s/brown/green/
quote> s/dog/cat/
quote> ' sedData1.txt
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.

一定不要忘了,要在封尾單引號所在行結束命令,bash shell一旦發現了封尾的單引號,就會執行命令。

從文件中讀取編輯器命令

如果有大量要處理的sed命令,將它們放入一個單獨的文件執行通常會更方便一些。
在sed命令中使用-f選項來指定文件。

$ cat script1.sed
s/brown/green/
s/fox/elephant/
s/dog/cat/
$
$ sed -f script1.sed sedData1.txt
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.

在這種情況下,不用在每個命令後添加分號,因爲sed編輯器知道每行都是一條獨立的命令。

小竅門
我們很容易會把sed編輯器腳本文件與bash shell的其他腳本文件搞混,爲了避免這種情況,可以使用 .sed 作爲sed命令腳本文件的擴展名。

可以集成到腳本中的基本命令和功能

更多的替換選項

我們上面已經掌握瞭如何用s命令(substitute)在行中替換文本,這個命令還有其他選項讓處理文本變得更簡單。
替換標記
s命令的替換標記在替換命令字符串之後設置 s/pattern/replacement/flags,有四種可用的替換標記:

  • 數字,表明新文本將替換第幾處模式匹配到的地方;
  • g,表明新文本將替換所有匹配到的文本;
  • p,表明原先行的內容要打印出來;
  • w file,將替換的結果寫到文件中。
$ cat test1.txt
This is a test line of the test script.
This is the second test line of the test script.
$
$ sed 's/test/trial/2' test1.txt
This is a test line of the trial script.
This is the second test line of the trial script.
$
$ sed 's/test/trial/g' test1.txt
This is a trial line of the trial script.
This is the second trial line of the trial script.
$ 
$ cat test2.txt
This is a test line.
This is a different line.
$
$ sed -n 's/test/trial/p' test2.txt
This is a trial line.
$
$ sed 's/test/trial/w test.txt' test2.txt
This is a trial line.
This is a different line.
$
$ cat test.txt
This is a trial line.

特別說明:
-n選項禁止sed編輯器輸出,但p替換標記會輸出修改過的行,二者結合使用效果就是隻輸出被替換命令修改過的行。
w替換標記會產生同樣的輸出,但會將輸出保存到指定文件中。

替換字符
有時我們會在文本字符串中遇到一些不太方便在替換模式中使用的字符,比如正斜線(/)。替換文件中的路徑名就會變得比較麻煩。比如:

$ sed 's/\bin\/bash/\/bin\/csh/' /etc/passwd

遇到正斜線的時候,看到上面這個替換命令,瞬間覺得頭暈眼花。
不過不用擔心啦,sed編輯器允許選擇其它字符來作爲命令中的字符串分隔符:

sed 's@bin/bash@/bin/csh@' /etc/passwd

提示:
上面的字符串分隔符,你可以使用任意字符,但是要保證一致,不可以sed ‘s@bin/bash#/bin/csh!’ /etc/passwd,這樣的是不正確的哦。

$ sed 's@bin/bash#/bin/csh!' /etc/passwd
sed: 1: "s@bin/bash#/bin/csh!": unterminated substitute pattern

使用地址

默認情況下,在sed編輯器中使用的命令會作用於文本數據的所有行。如果只想將命令作用於特定行或某些行,我們就要使用行尋址(line addressing)
在sed編輯器中有兩種形式的行尋址:

  • 以數字形式表示行區間;
  • 用文本模式來過濾出行;

以上兩種形式都使用相同的格式來指定地址:
[address] command
也可以將特定地址的多個命令分組:
address {
command1
command2
command3
}
sed編輯器會將指定的每條命令作用到匹配指定地址的行上。

數字方式的行尋址

使用數字方式的行尋址時,可以用行在文本流中的行位置來引用。sed編輯器將文本流中的第一行編號爲1,然後繼續按序爲後面的行分配行號。
在命令中指定的地址可以是單個行號,或者用起始行號、逗號以及結尾行號指定一定區間範圍內的行,如果並不知到文本中到底有多少行數據,可以使用美元符號💲指定從某行開始到文本結尾的所有行。

$ sed '2s/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$
$ sed '2,4s/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
$
$ sed '3,$s/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.

使用文本模式過濾器

sed編輯器允許指定文本模式來過濾出命令要作用的行,格式如下:
/pattern/command
要注意的是,必須用正斜線把pattern包起來,這樣sed就會將該命令作用到包含指定文本模式的行上。

$ grep nobody /etc/passwd
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
$
$ sed '/nobody/s/bash/csh/' /etc/passwd
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
[....]

上面的命令只作用到匹配文本模式的行上。雖然使用固定文本模式能幫我們過濾出特定的值,但是它的作用還是有限,所以sed編輯器在文本模式中提供了正則表達式的特性來幫助創建匹配效果更好的模式(這裏不展開正則表達式的相關知識)。

命令組合

如果需要在單行上執行多條命令,可以使用花括號將多條命令組合到一起。

$ sed '2{
quote> s/brown/green/
quote> s/fox/elephant/
quote> s/dog/cat/
quote> }' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick green elephant jumps over the lazy cat.
The quick brown fox jumps over the lazy dog.
$
$ sed '2,${
s/brown/green/
s/fox/elephant/
s/dog/cat/
}' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.

組合中的三條命令都會作用到該地址上,當然,我們還可以指定行區間。

刪除和修改行

當然,除了文本替換外,sed還提供了刪除和修改行的命令。
刪除命令d,會刪除匹配指定尋址模式的所有行。
使用刪除命令要特別小心,如果你忘記加入尋址模式的話,流中的所有文本行 都會被刪除(當然原文件內容不會發生任何改變,只是文本流中的內容會被刪除)

$  cat sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$
$ sed 'd' sedData1.txt
$
$ cat sedData2.txt
This is line no.1
This is line no.2
This is line no.3
This is line no.4
This is line no.5
$ sed '3d' sedData2.txt
This is line no.1
This is line no.2
This is line no.4
This is line no.5
$ sed '1, 3d' sedData2.txt
This is line no.4
This is line no.5
$ sed '3, $d' sedData2.txt
This is line no.1
This is line no.2
$ sed sed '/1/,/3/d' sedData2.txt
This is line no.4
This is line no.5
$ 

修改(change)命令允許修改數據流中的整行文本的內容。它的工作機制是,你必須在sed命令中單獨指定新的行

$ sed '3c\
This is a changed line of the text.' sedData2.txt
This is line no.1
This is line no.2
This is a changed line of the text.
This is line no.4
This is line no.5
$
$ sed '2,3c\
This is a changed line of the text.' sedData2.txt
This is line no.1
This is a changed line of the text.
This is line no.4
This is line no.5

示例說明:在第一個例子中,sed編輯器會修改第三行中的文本,也可以用文本模式來尋找,比如:
sed ‘/no.3/c
This is a changed line of the text.’ sedData2.txt
文本模式修改命令會修改它匹配的數據流中的任意文本行。
第二個例子,使用了地址區間,但結果是sed編輯器用一行文本替換了數據流中的兩行文本,而不是逐一修改這兩行文本。

插入和追加文本

sed編輯器允許向數據流插入和追加文本行,兩個操作的區別是:

  • 插入(insert)命令(i)會在指定行前增加一個新行;
  • 追加(append)命令(a)會在指定行後增加一個新行;

命令格式:
sed ‘[address] command
new line’
new line中的文本會出現在sed編輯器輸出中你指定的位置。

$  echo "line 2" | sed 'i\
> line 1'
line 1
line 2
$
$  echo "line 2" | sed 'a\
line 1'
line 2
line 1

通過上面的例子,我們可以在文本前面或者後面添加文本,那麼想要在文本中間插入文本要怎麼做呢?
這種情況下,我們必須使用尋址來告訴sed編輯器,我們要讓文本出現在什麼位置。所以,在使用這些命令的時候只指定一個行地址,可以匹配一個數字行號或文本模式,但是不能使用地址區間,這很說的通,因爲不管你是插入還是追加,你只能是以單個行爲緯度來實現這個操作,而不是在行區間的前面或後面。

$ sed '3i\
quote> This is an inserted line.' sedData2.txt
This is line no.1
This is line no.2
This is an inserted line.
This is line no.3
This is line no.4
$
$ sed '3a\
This is an appended line.' sedData2.txt
This is line no.1
This is line no.2
This is line no.3
This is an appended line.
This is line no.4
$
$ sed '3i\
quote> This is line 1 of inserting.\
quote> This is line 2 of inserting.' sedData2.txt
This is line no.1
This is line no.2
This is line 1 of inserting.
This is line 2 of inserting.
This is line no.3
This is line no.4

特別說明:
如果要插入或追加多行文本,就必須對要插入或追加的每一行新文本後面使用反斜線,知道最後一行。

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