Shell Script sed編輯器

目錄

命令行使用

Sed操作命令

多行操作

保持空間

排除命令

改變流

模式替代

重定向sed 的輸出

sed 實用工具


交互式文本編輯器(vim)可以用鍵盤命令來交互式地插入、刪除或替換數據中的文本

流編輯器(sed和gawk)則會在編輯器處理數據之前基於預先提供的一組命令來編輯數據流

命令行使用

sed編輯器會執行下列操作。在流編輯器將所有命令與一行數據匹配完畢後,它會讀取下一行數據並重復這個過程。在流編輯器處理完流中的所有數據行後,它就會終止。 

(1) 一次從輸入中讀取一行數據。
(2) 根據所提供的編輯器命令匹配數據。
(3) 按照命令修改流中的數據。
(4) 將新的數據輸出到STDOUT。

sed options script file
sed命令選項
-e script 在處理輸入時,將script中指定的命令添加到已有命令中
-f file 在處理輸入時,將file中指定的命令添加到已有的命令中
-n 不產生命令輸出,使用print命令完成輸出

默認情況下,sed編輯器會將指定的命令應用到STDIN輸入流上。這樣你可以直接將數據通過管道輸入sed編輯器處理。

$ echo "This is a test" | sed 's/test/big test/'
This is a big test    #s命令會用斜線間指定的第二個文本字符串來替換第一個文本字符串模式
$ cat data1.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/' data1.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編輯器並不會修改文本文件的數據。它只會將修改後的數據發送到STDOUT。如果你查看原來的文本文件,它仍然保留着原始數據。

在sed命令行上執行多個命令時,只要用-e選項就可以了,命令之間必須用分號隔開,並且在命令末尾和分號之間不能有空格

$ sed -e 's/brown/green/; s/dog/cat/' data1.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編輯器命令列表),bash會繼續提示你輸入更多命令,直到輸入了標示結束的單引號。

$ sed -e '
> s/brown/green/
> s/fox/elephant/
> s/dog/cat/' data1.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命令中用-f選項來指定文件。sed編輯器知道每行都是一條單獨的命令。

$ cat script1.sed
s/brown/green/
s/fox/elephant/
s/dog/cat/
$
$ sed -f script1.sed data1.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操作命令

  • 替換標記

 替換命令在替換多行中的文本時能正常工作,但默認情況下它只替換每行中出現的第一處。要讓替換命令能夠替換一行中不同地方出現的文本必須使用替換標記。

s/pattern/replacement/flags

數字,表明新文本將替換第幾處模式匹配的地方;

$ sed 's/test/trial/2' data4.txt

g,表明新文本將會替換所有匹配的文本;

$ sed 's/test/trial/g' data4.txt

p,會打印與替換命令中指定的模式匹配的行;通常會和sed的-n選項一起使用。-n選項將禁止sed編輯器輸出。但p替換標記會輸出修改過的行。將二者配合使用的效果就是隻輸出被替換命令修改過的行

$ sed -n 's/test/trial/p' data5.txt
$ sed -n '/number 3/p' data6.txt
This is line number 3.
$ sed -n '/3/{
> p                    #在修改行之前顯示該行
> s/line/test/p
> }' data6.txt
This is line number 3.
This is test number 3.
$

=命令會打印行在數據流中的當前行號。

$ sed -n '/number 4/{
> =
> p
> }' data6.txt
4
This is line number 4.
$

[address]w filename,將替換的結果寫到文件中。 

$ sed 's/test/trial/w test.txt' data5.txt    #將修改後的行輸出到test.txt

$ sed -n '/Browncoat/w Browncoats.txt' data11.txt    #只將包含文本模式的數據行寫入目標文件
$ cat Browncoats.txt
Blum, R Browncoat
Bresnahan, C Browncoat
$

  [address]r filename,將一個獨立文件中的數據插入到數據流中

$ cat data12.txt
This is an added line.
This is the second added line.
$
$ sed '3r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an added line.
This is the second added line.
$ sed '/number 2/r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is an added line.
This is the second added line.
This is line number 3.

$

 

有時替換文件中的路徑名會比較麻煩,例如正斜線(/)。想用C shell替換/etc/passwd文件中的bash shell:由於正斜線通常用作字符串分隔符,因而如果它出現在了模式文本中的話,必須用反斜線來轉義

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

sed編輯器允許選擇其他字符來作爲替換命令中的字符串分隔符:感嘆號被用作字符串分隔符

$ sed 's!/bin/bash!/bin/csh!' /etc/passwd
  • 按行尋址操作

默認情況下,在sed編輯器中使用的命令會作用於文本數據的所有行。如果只想將命令作用於特定行或某些行,則必須用行尋址。在sed編輯器中有兩種形式的行尋址:1. 以數字形式表示行區間;2. 用文本模式來過濾出行

 兩種形式都使用相同的格式來指定地址:

[address]command
#將特定地址的多個命令分組
address {
command1
command2
command3
}
  • 數字方式的行尋址

sed編輯器會將文本流中的第一行編號爲1

$ sed '2s/dog/cat/' data1.txt    #作用到指定行號
$ sed '2,3s/dog/cat/' data1.txt    #行地址區間
$ sed '2,$s/dog/cat/' data1.txt    #從某行開始的所有行,可以用特殊地址——美元符
  •  使用文本模式過濾器

sed編輯器允許指定文本模式來過濾出命令要作用的行。/pattern/command.必須用正斜線將要指定的pattern封起來。sed編輯器會將該命令作用到包含指定文本模式的行上.你想只修改用戶Samantha的默認shell

$ grep Samantha /etc/passwd
Samantha:x:502:502::/home/Samantha:/bin/bash
$
$ sed '/Samantha/s/bash/csh/' /etc/passwd    #sed編輯器在文本模式中採用了一種稱爲正則表達式
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[...]
Christine:x:501:501:Christine B:/home/Christine:/bin/bash
Samantha:x:502:502::/home/Samantha:/bin/csh
Timothy:x:503:503::/home/Timothy:/bin/bash
$
  • 命令組合
$ sed '2{
> s/fox/elephant/
> s/dog/cat/
> }' data1.txt
  • 刪除行

$ sed 'd' data1.txt    #刪除所有文本行
$ sed '3d' data6.txt    #刪除第三行
$ sed '/number 1/d' data6.txt    #模式匹配特性也適用於刪除命令,刪掉包含匹配指定模式的行
  • 插入和附加文本

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

$ sed '3i\
> This is an inserted line.' data6.txt
This is line number 1.
This is line number 2.
This is an inserted line.
This is line number 3.

#要插入或附加多行文本,就必須對要插入或附加的新文本中的每一行使用反斜線,直到最後一行。
sed '1i\
> This is one line of new text.\
> This is another line of new text.' data6.txt

附加(append)命令(a)會在指定行後增加一個新行

$ sed '3a\
> This is an appended line.' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an appended line.
$ sed '$a\
> This is a new line of text.' data6.txt    #美元符代表最後一行
  • 修改行

change命令允許修改數據流中整行文本的內容 

$ sed '3c\
> This is a changed line of text.' data6.txt
This is line number 1.
This is line number 2.
This is a changed line of text.
This is line number 4.
$ sed '/number 3/c\                #用文本模式來尋址
> This is a changed line of text.' data6.txt
$ sed '2,3c\                        # 一行文替換兩行文本
> This is a new line of text.' data6.txt
  • 轉換字符

轉換(transform)命令(y)是唯一可以處理單個字符的sed編輯器命令 :[address]y/inchars/outchars/轉換命令會對inchars和outchars值進行一對一的映射。inchars中的第一個字符會被轉換爲outchars中的第一個字符,第二個字符會被轉換成outchars中的第二個字符。這個映射過程會一直持續到處理完指定字符。如果inchars和outchars的長度不同,則sed編輯器會產生一條錯誤消息。

$ sed 'y/123/789/' data8.txt
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4.

多行操作

之前接觸的sed編輯器命令都是針對單行數據執行操作的,sed編輯器包含了三個可用來處理多行文本的特殊命令。

N:將數據流中的下一行加進來創建一個多行組(multiline group)來處理。
D:刪除多行組中的一行。
P:打印多行組中的一行。

  • next 命令

單行的next命令

小寫的n命令會告訴sed編輯器移動到數據流中的下一文本行,而不用重新回到命令的最開始再執行一遍。目標是刪除首行之後的空白行,而留下最後一行之前的空白行。腳本要查找含有單詞header的那一行。找到之後,n命令會讓sed編輯器移動到文
本的下一行,也就是那個空行。sed編輯器會繼續執行命令列表,該命令列表使用d命令來刪除空白行。

$ cat data1.txt
This is the header line.

This is a data line.

This is the last line.
$
$ sed '/header/{n ; d}' data1.txt
This is the header line.
This is a data line.

This is the last line.
$

合併文本行

多行版本的next命令(用大寫N)會將下一文本行添加到模式空間中已有的文本後。這樣的作用是將數據流中的兩個文本行合併到同一個模式空間中。文本行仍然用換行符分隔,但sed編輯器現在會將兩行文本當成一行來處理。

sed編輯器腳本查找含有單詞first的那行文本。找到該行後,它會用N命令將下一行合併到那行,然後用替換命令s將換行符替換成空格。結果是,文本文件中的兩行在sed編輯器的輸出中成了一行。

$ cat data2.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$
$ sed '/first/{ N ; s/\n/ / }' data2.txt
This is the header line.
This is the first data line. This is the second data line.
This is the last line.
$

如果要在數據文件中查找一個可能會分散在兩行中的文本短語的話,這是個很實用的應用程序。

$ cat data3.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.
$
$ sed 'N ; s/System Administrator/Desktop User/' data3.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.
$
$ sed 'N ; s/System.Administrator/Desktop User/' data3.txt    #通配符模式(.)來匹配空格和換行符
On Tuesday, the Linux Desktop User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.
$

若不想將第一第二行合併可以採用下面方法

$ sed 'N
> s/System\nAdministrator/Desktop\nUser/
> s/System Administrator/Desktop User/
> ' data3.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.
$

由於System Administrator文本出現在了數據流中的最後一行,N命令會錯過它,因爲沒有其他行可讀入到模式空間跟這行合併。你可以輕鬆地解決這個問題——將單行命令放到N命令前面,並將多行命令放到N命令後面,像這樣:

$ sed '
> s/System Administrator/Desktop User/
> N
> s/System\nAdministrator/Desktop\nUser/
> ' data4.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All Desktop Users should attend.
$
  • 多行刪除命令

將單行刪除命令(d)和N命令一起使用時,刪除命令會在不同的行中查找單詞System和Administrator,然後在模式空間中將兩行都刪掉。

$ sed 'N ; /System\nAdministrator/d' data4.txt
All System Administrators should attend.
$

sed編輯器提供了多行刪除命令D,它只刪除模式空間中的第一行。該命令會刪除到換行符(含換行符)爲止的所有字符。

$ sed 'N ; /System\nAdministrator/D' data4.txt
Administrator's group meeting will be held.
All System Administrators should attend.
$

刪除數據流中出現在第一行前的空白行。sed編輯器腳本會查找空白行,然後用N命令來將下一文本行添加到模式空間。如果新的模式空間內容含有單詞header,則D命令會刪除模式空間中的第一行。如果不結合使用N命令和D命令,就不可能在不刪除其他空白行的情況下只刪除第一個空白行。

$ cat data5.txt

This is the header line.
This is a data line.

This is the last line.
$
$ sed '/^$/{N ; /header/D}' data5.txt
This is the header line.
This is a data line.

This is the last line.
$
  • 多行打印命令

多行打印命令(P)沿用了同樣的方法。它只打印多行模式空間中的第一行。這包括模式空間中直到換行符爲止的所有字符。用-n選項來阻止腳本輸出時,它和顯示文本的單行p命令的用法大同小異。

$ sed -n 'N ; /System\nAdministrator/P' data3.txt
On Tuesday, the Linux System
$

保持空間

模式空間(pattern space)是一塊活躍的緩衝區,在sed編輯器執行命令時它會保存待檢查的文本。但它並不是sed編輯器保存文本的唯一空間。sed編輯器有另一塊稱作保持空間(hold space)的緩衝區域。在處理模式空間中的某些行時,可以用保持空間來臨時保存一些行。有5條命令可用來操作保持空間,

sed編輯器的保持空間命令
h 將模式空間複製到保持空間
H 將模式空間附加到保持空間
g 將保持空間複製到模式空間
G 將保持空間附加到模式空間
x 交換模式空間和保持空間的內容

通常,在使用h或H命令將字符串移動到保持空間後,最終還要用g、G或x命令將保存的字符串移回模式空間(否則,你就不用在一開始考慮保存它們了)。

$ cat data2.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$
$ sed -n '/first/ {h ; p ; n ; p ; g ; p }' data2.txt
This is the first data line.
This is the second data line.
This is the first data line.
$
$ sed -n '/first/ {h ; n ; p ; g ; p }' data2.txt
This is the second data line.
This is the first data line.
$

排除命令

感嘆號命令(!)用來排除(negate)命令,也就是讓原本會起作用的命令不起作用。普通p命令只打印data2文件中包含單詞header的那行。加了感嘆號之後:除了包含單詞header那一行外,文件中其他所有的行都被打印出來了。

$ sed -n '/header/!p' data2.txt
This is the first data line.
This is the second data line.
This is the last line.
$

使用這種方法,你可以反轉數據流中文本行的順序,

將保持空間文本附加到模式空間文本後面。這可以用G命令完成。唯一的問題是你不想將保持空間附加到要處理的第一行文本後面。這可以用感嘆號命令輕鬆解決: 1!G

$ cat data2.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$
$ sed -n '{1!G ; h ; $p }' data2.txt        #當{}前沒命令,本身就是一行行操作
This is the last line.
This is the second data line.
This is the first data line.
This is the header line.
$

改變流

sed編輯器會從腳本的頂部開始,一直執行到腳本的結尾。sed編輯器提供了一個方法來改變命令腳本的執行流程,其結果與結構化編程類似。

  • 分支

已經知道如何用感嘆號命令來排除作用在某行上的命令。sed編輯器提供了一種方法,可以基於地址、地址模式或地址區間排除一整塊命令。這允許你只對數據流中的特定行執行一組命令。分支(branch)命令b的格式如下:

[address]b [label]

address參數決定了哪些行的數據會觸發分支命令。label參數定義了要跳轉到的位置。如果沒有加label參數,跳轉命令會跳轉到腳本的結尾。

$ cat data2.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$
$ sed '{2,3b ; s/This is/Is this/ ; s/line./test?/}' data2.txt
Is this the header test?            #分支命令在數據流中的第2行和第3行處跳過了兩個替換命令
This is the first data line.
This is the second data line.
Is this the last test?
$

要是不想直接跳到腳本的結尾,可以爲分支命令定義一個要跳轉到的標籤。標籤以冒號開始,最多可以是7個字符長度。

$ sed '{/first/b jump1 ; s/This is the/No jump on/
> :jump1                            #定義jump1
> s/This is the/Jump here on/}' data2.txt
No jump on header line
Jump here on first data line        #檢測到first,運行jump1的命令行
No jump on second data line
No jump on last line
$

分支不僅可以轉到sed腳本後面的標籤上。也可以跳轉到腳本中靠前面的標籤上,這樣就達到了循環的效果。 

$ echo "This, is, a, test, to, remove, commas." | sed -n '{
> :start
> s/,//1p                    # 腳本的每次迭代都會刪除文本中的第一個逗號,並打印字符串
> b start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
^C
$

這個腳本有個問題:它永遠不會結束。這就形成了一個無窮循環,不停地查找逗號,直到使用Ctrl+C組合鍵發送一個信號,手動停止這個腳本。要防止這個問題,可以爲分支命令指定一個地址模式來查找。如果沒有模式,跳轉就應該結束。 

$ echo "This, is, a, test, to, remove, commas." | sed -n '{
> :start
> s/,//1p          
> /,/b start            #最後一個逗號被刪除後,分支命令不會再執行
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
$
  • 測試

類似於分支命令,測試(test)命令(t)也可以用來改變sed編輯器腳本的執行流程。測試命令會根據替換命令的結果跳轉到某個標籤,而不是根據地址進行跳轉。如果替換命令成功匹配並替換了一個模式,測試命令就會跳轉到指定的標籤。如果替換命令未能匹配指定的模式,測試命令就不會跳轉。

[address]t [label]

測試命令提供了對數據流中的文本執行基本的if-then語句的一個低成本辦法。舉個例子,如果已經做了一個替換,不需要再做另一個替換。第一個替換命令會查找模式文本first。如果匹配了行中的模式,它就會替換文本,而且測試命令會跳過後面的替換命令。如果第一個替換命令未能匹配模式,第二個替換命令就會被執行。

$ sed '{
> s/first/matched/
> t
> s/This is the/No match on/
> }' data2.txt
No match on header line
This is the matched data line
No match on second data line
No match on last line
$

有了測試命令,你就能結束上一節中用分支命令形成的無限循環。當無需替換時,測試命令不會跳轉而是繼續執行剩下的腳本。

$ echo "This, is, a, test, to, remove, commas. " | sed -n '{
> :start
> s/,//1p
> t start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
$

模式替代

舉個例子,假如你想在行中匹配的單詞兩邊上放上引號。

$ echo "The cat sleeps in his hat." | sed 's/cat/"cat"/'
The "cat" sleeps in his hat.

但如果你在模式中用通配符(.)來匹配多個單詞呢?我們想要的輸出結果是The "cat" sleeps in his "hat".

$ echo "The cat sleeps in his hat." | sed 's/.at/".at"/g'
The ".at" sleeps in his ".at".
$

模式字符串用點號通配符來匹配at前面的一個字母。遺憾的是,用於替代的字符串無法匹配已匹配單詞中的通配符字符。

  • &符號

 &符號可以用來代表替換命令中的匹配的模式。不管模式匹配的是什麼樣的文本,你都可以在替代模式中使用&符號來使用這段文本。

$ echo "The cat sleeps in his hat." | sed 's/.at/"&"/g'
The "cat" sleeps in his "hat".
$
  • 替代單獨的單詞

&符號會提取匹配替換命令中指定模式的整個字符串。有時你只想提取這個字符串的一部分。sed編輯器用圓括號來定義替換模式中的子模式。你可以在替代模式中使用特殊字符來引用每個子模式。替代字符由反斜線和數字組成。sed編輯器會給第一個子模式分配字符\1,給第二個子模式分配字符\2

當在替換命令中使用圓括號時,必須用轉義字符將它們標示爲分組字符而不是普通的圓括號。這跟轉義其他特殊字符正好相反。

這個替換命令用一對圓括號將單詞System括起來,將其標示爲一個子模式。然後它在替代模式中使用\1來提取第一個匹配的子模式。 

$ echo "The System Administrator manual" | sed '
> s/\(System\) Administrator/\1 User/'    #System User替換System Administrator
The System User manual
$

 如果需要用一個單詞來替換一個短語,而這個單詞剛好是該短語的子字符串,但那個子字符串碰巧使用了通配符,這時使用子模式會方便很多。在這種情況下,你不能用&符號,因爲它會替換整個匹配的模式。子模式提供了答案,允許你選擇將模式中的某部分作爲替代模式。

$ echo "That furry cat is pretty" | sed 's/furry \(.at\)/\1/'    #cat替換furry cat
That cat is pretty
$
$ echo "That furry hat is pretty" | sed 's/furry \(.at\)/\1/'    #hat替換furry hat
That hat is pretty
$

當需要在兩個或多個子模式間插入文本時,這個特性尤其有用。這裏有個腳本,它使用子模式在大數字中插入逗號。 這個腳本將匹配模式分成了兩部分(.*[0-9])和([0-9]{3})。這個模式會查找兩個子模式。第一個子模式是以數字結尾的任意長度的字符。第二個子模式是若干組三位數字。如果這個模式在文本中找到了,替代文本會在兩個子模式之間加一個逗號,每個子模式都會通過其位置來標示。這個腳本使用測試命令來遍歷這個數字,直到放置好所有的逗號。

$ echo "1234567" | sed '{
> :start
> s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/        #兩個子模式之間加一個逗號
> t start
> }'
1,234,567
$

重定向sed 的輸出

默認情況下,sed編輯器會將腳本的結果輸出到STDOUT上。你可以在shell腳本中使用各種標準方法對sed編輯器的輸出進行重定向。可以在腳本中用$()將sed編輯器命令的輸出重定向到一個變量中,以備後用。

$ cat fact.sh
#!/bin/bash
factorial=1
counter=1
number=$1
while [ $counter -le $number ]
do
    factorial=$[ $factorial * $counter ]
    counter=$[ $counter + 1 ]
done
result=$(echo $factorial | sed '{
:start
s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
t start
}')

echo "The result is $result"
$

sed 實用工具

  • 加倍行間距

這個技巧的關鍵在於保持空間的默認值。記住,G命令會簡單地將保持空間內容附加到模式空間內容後。當啓動sed編輯器時,保持空間只有一個空行。將它附加到已有行後面,你就在已有行後面創建了一個空白行。 

$ sed 'G' data2.txt
This is the header line.

This is the first data line.

This is the second data line.

This is the last line.

$

這個腳本在數據流的最後一行後面也加了一個空白行,使得文件的末尾也產生了一個空白行。如果你不想要這個空白行,可以用排除符號(!)和尾行符號($)來確保腳本不會將空白行加到數據流的最後一行後面。只要該行不是最後一行,G命令就會附加保持空間內容。當sed編輯器到了最後一行時,它會跳過G命令。

$ sed '$!G' data2.txt
This is the header line.

This is the first data line.

This is the second data line.

This is the last line.
$

如果文本文件已經有一些空白行,但你想給所有行加倍行間距要怎麼辦呢?首先刪除數據流中的所有空白行,然後用G命令在所有行後插入新的空白行

$ cat data6.txt
This is line one.
This is line two.

This is line three.
This is line four.
$
$ sed '/^$/d ; $!G' data6.txt
This is line one.

This is line two.

This is line three.

This is line four.
$
  • 給文件中的行編號

這可能有點難看,因爲行號是在數據流中實際行的上方。比較好的解決辦法是將行號和文本放在同一行。 

$ sed '=' data2.txt
1
This is the header line.
2
This is the first data line.
3
This is the second data line.
4
This is the last line.
$

你已經知道如何用N命令合併行,在sed腳本中使用這個命令應該不難。在獲得了等號命令的輸出之後,你可以通過管道將輸出傳給另一個sed編輯器腳本,它會使用N命令來合併這兩行。還需要用替換命令將換行符更換成空格或製表符。最終的解決辦法看起來如下

$ sed '=' data2.txt | sed 'N; s/\n/ /'
1 This is the header line.
2 This is the first data line.
3 This is the second data line.
4 This is the last line.
$

有些bash shell命令也可以添加行號,但它們會另外加入一些東西

$ nl data2.txt
1 This is the header line.
2 This is the first data line.
3 This is the second data line.
4 This is the last line.
$
$ cat -n data2.txt
1 This is the header line.
2 This is the first data line.
3 This is the second data line.
4 This is the last line.
$
  • 打印末尾行

已經知道如何用p命令來打印數據流中所有的或者是匹配某個特定模式的行。如果只需處理一個長輸出(比如日誌文件)中的末尾幾行。美元符代表數據流中最後一行,所以只顯示最後一行很容易。
 

$ sed -n '$p' data2.txt
This is the last line.
$

那麼,如何用美元符來顯示數據流末尾的若干行呢?答案是創建滾動窗口

滾動窗口是檢驗模式空間中文本行塊的常用方法,它使用N命令將這些塊合併起來。N命令將下一行文本附加到模式空間中已有文本行後面。一旦你在模式空間有了一個10行的文本塊,你可以用美元符來檢查你是否已經處於數據流的尾部。如果不在,就繼續向模式空間增加行,同時刪除原來的行(記住,D命令會刪除模式空間的第一行)。 

通過循環N命令和D命令,你在向模式空間的文本行塊增加新行的同時也刪除了舊行。分支命令非常適合這個循環。要結束循環,只要識別出最後一行並用q命令退出就可以了。

$ sed '{
> :start
> $q ; N ; 11,$D    #退出(quit)命令;N命令會將下一行附加到模式空間中當前行之後;當前行在第10行後面,11,$D命令會刪除模式空間中的第一行
> b start
> }' data7.txt
This is line 6.
This is line 7.
This is line 8.
This is line 9.
This is line 10.
This is line 11.
This is line 12.
This is line 13.
This is line 14.
This is line 15.
$
  • 刪除行

刪除連續的空白行

/./,/^$/!d

刪除連續空白行的關鍵在於創建包含一個非空白行和一個空白行的地址區間。如果sed編輯器遇到了這個區間,它不會刪除行。但對於不匹配這個區間的行(兩個或更多的空白行),它會刪除這些行。

區間是/./到/^$/。區間的開始地址會匹配任何含有至少一個字符的行。區間的結束地址會匹配一個空行。在這個區間內的行不會被刪除。

刪除開頭的空白行

/./,$!d

這個區間從含有字符的行開始,一直到數據流結束。在這個區間內的任何行都不會從輸出中刪除。這意味着含有字符的第一行之前的任何行都會刪除。

刪除結尾的空白行

sed '{
:start
/^\n*$/{$d; N; b start }
}'

地址模式能夠匹配只含有一個換行符的行。如果找到了這樣的行,而且還是最後一行,刪除命令會刪掉它。如果不是最後一行,N命令會將下一行附加到它後面,分支命令會跳到循環起始位置重新開始。

  • 刪除HTML 標籤

標準的HTML Web頁面包含一些不同類型的HTML標籤,標明瞭正確顯示頁面信息所需要的格式化功能。HTML標籤由小於號和大於號來識別。大多數HTML標籤都是成對出現的:一個起始標籤(比如<b>用來加粗),以及另一個結束標籤(比如</b>用來結束加粗)。

$ cat data11.txt
<html>
<head>
<title>This is the page title</title>
</head>
<body>
<p>
This is the <b>first</b> line in the Web page.
This should provide some <i>useful</i>
information to use in our sed script.
</body>
</html>
$

乍一看,你可能認爲刪除HTML標籤的辦法就是查找以小於號(<)開頭、大於號(>)結尾且其中有數據的文本字符串。
注意,標題文本以及加粗和傾斜的文本都不見了。sed編輯器將這個腳本忠實地理解爲小於號和大於號之間的任何文本,且包括其他的小於號和大於號。每次文本出現在HTML標籤中(比如<b>first</b>),這個sed腳本都會刪掉整個文本。

$ sed 's/<.*>//g' data11.txt
This is the line in the Web page.
This should provide some
information to use in our sed script.
$

這個問題的解決辦法是讓sed編輯器忽略掉任何嵌入到原始標籤中的大於號。要這麼做的話,你可以創建一個字符組來排除大於號。

$ sed 's/<[^>]*>//g' data11.txt
This is the page title
This is the first line in the Web page.
This should provide some useful
information to use in our sed script.
$

現在好一些了。要想看起來更清晰一些,可以加一條刪除命令來刪除多餘的空白行。

$ sed 's/<[^>]*>//g ; /^$/d' data11.txt
This is the page title
This is the first line in the Web page.
This should provide some useful
information to use in our sed script.
$

 

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