流編輯器 - 快速指南




流編輯器 - 概述

縮寫 SED 代表 **Stream EDitor**。它是一個簡單但強大的實用程式,可以解析文字並無縫地轉換它。SED 由貝爾實驗室的 Lee E. McMahon 於 1973-74 年開發。如今,它執行在所有主要的作業系統上。

McMahon 編寫了一個通用的面向行的編輯器,最終成為了 SED。SED 借鑑了 ed 編輯器的語法和許多有用的功能。從一開始,它就支援正則表示式。SED 接受來自檔案以及管道的輸入。此外,它還可以接受來自標準輸入流的輸入。

SED 由自由軟體基金會 (FSF) 編寫和維護,並由 GNU/Linux 釋出。因此,它通常被稱為 **GNU SED**。對於新手使用者來說,SED 的語法可能看起來很神秘。但是,一旦你熟悉了它的語法,你就可以用幾行 SED 指令碼解決許多複雜的任務。這就是 SED 的魅力所在。

SED 的典型用途

SED 可以以多種不同的方式使用,例如

  • 文字替換,
  • 選擇性列印文字檔案,
  • 就地編輯文字檔案,
  • 非互動式編輯文字檔案,等等。

流編輯器 - 環境

本章介紹如何在你的 GNU/Linux 系統上設定 SED 環境。

使用包管理器安裝

通常,SED 在大多數 GNU/Linux 發行版中預設可用。使用 **which** 命令來確定它是否在你的系統上存在。如果不存在,則使用如下所示的 **apt** 包管理器在基於 Debian 的 GNU/Linux 上安裝 SED

[jerry]$ sudo apt-get install sed 

安裝後,確保可以透過命令列訪問 SED。

[jerry]$ sed --versio

執行上述程式碼後,你將得到以下結果

sed (GNU sed) 4.2.2 
Copyright (C) 2012 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later . 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law.  
Written by Jay Fenlason, Tom Lord, Ken Pizzini, 
and Paolo Bonzini. 
GNU sed home page: . 
General help using GNU software: . 
E-mail bug reports to: . 
Be sure to include the word "sed" somewhere in the "Subject:" field.

類似地,要在基於 RPM 的 GNU/Linux 上安裝 SED,請使用如下所示的 yum 包管理器

[root]# yum -y install sed

安裝後,確保可以透過命令列訪問 SED。

[root]# sed --version

執行上述程式碼後,你將得到以下結果

GNU sed version 4.2.1 
Copyright (C) 2009 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions.  There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, 
to the extent permitted by law.  
GNU sed home page: . 
General help using GNU software: . 
E-mail bug reports to: . 
Be sure to include the word "sed" somewhere in the "Subject:" field.

從原始碼安裝

由於 GNU SED 是 GNU 專案的一部分,因此其原始碼可免費下載。我們已經瞭解瞭如何使用包管理器安裝 SED。現在讓我們瞭解如何從其原始碼安裝 SED。

以下安裝適用於任何 GNU/Linux 軟體,以及大多數其他免費提供的程式。以下是安裝步驟

  • 從可靠的地方下載原始碼。命令列實用程式 **wget** 用於此目的。

  • [jerry]$ wget ftp://ftp.gnu.org/gnu/sed/sed-4.2.2.tar.bz2
    
  • 解壓縮並提取下載的原始碼。

  • [jerry]$ tar xvf sed-4.2.2.tar.bz2 
    
  • 切換到目錄並執行 configure。

  • [jerry]$ ./configure 
    
  • 成功完成後,**configure** 將生成 Makefile。要編譯原始碼,請發出 **make** 命令。

  • [jerry]$ make
    
  • 你可以執行測試套件以確保構建是乾淨的。這是一個可選步驟。

  • [jerry]$ make check 
    
  • 最後,安裝 SED 實用程式。確保你擁有超級使用者許可權。

  • [jerry]$ sudo make install 
    

就是這樣!你已成功編譯並安裝了 SED。透過如下所示執行 **sed** 命令來驗證它

[jerry]$ sed --version

執行上述程式碼後,你將得到以下結果

sed (GNU sed) 4.2.2 
Copyright (C) 2012 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later . 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law.  
Written by Jay Fenlason, Tom Lord, Ken Pizzini, 
and Paolo Bonzini. 
GNU sed home page: . 
General help using GNU software: . 
E-mail bug reports to: . 
Be sure to include the word "sed" somewhere in the "Subject:" field.

流編輯器 - 工作流程

在本章中,我們將探討 SED 的確切工作原理。要成為一名專家級 SED 使用者,需要了解其內部機制。SED 遵循一個簡單的工作流程:讀取、執行和顯示。下圖描述了工作流程。

Stream Editor Workflow
  • **讀取**:SED 從輸入流(檔案、管道或 stdin)讀取一行並將其儲存在其稱為 **模式緩衝區** 的內部緩衝區中。

  • **執行**:所有 SED 命令都按順序應用於模式緩衝區。預設情況下,SED 命令應用於所有行(全域性),除非指定行地址。

  • **顯示**:將(修改後的)內容傳送到輸出流。傳送資料後,模式緩衝區將為空。

  • 上述過程重複,直到檔案耗盡。

注意事項

  • 模式緩衝區是 SED 使用的私有、記憶體中、易失性儲存區域。

  • 預設情況下,所有 SED 命令都應用於模式緩衝區,因此輸入檔案保持不變。GNU SED 提供了一種就地修改輸入檔案的方法。我們將在後面的章節中探討它。

  • 還有一個名為 **保持緩衝區** 的記憶體區域,它也是私有的、記憶體中的、易失性儲存區域。資料可以儲存在保持緩衝區中以供以後檢索。在每個迴圈結束時,SED 會刪除模式緩衝區的內容,但保持緩衝區的內容在 SED 迴圈之間保持持久。但是 SED 命令不能直接在保持緩衝區上執行,因此 SED 允許在保持緩衝區和模式緩衝區之間移動資料。

  • 最初,模式緩衝區和保持緩衝區都為空。

  • 如果沒有提供輸入檔案,則 SED 接受來自標準輸入流 (stdin) 的輸入。

  • 如果未提供地址範圍,則預設情況下 SED 對每一行進行操作。

示例

讓我們建立一個名為 **quote.txt** 的文字檔案,其中包含著名作家保羅·科埃略的一段引言。

[jerry]$ vi quote.txt 
There is only one thing that makes a dream impossible to achieve: the fear of failure. 
 - Paulo Coelho, The Alchemist

為了理解 SED 的工作流程,讓我們使用 SED 顯示檔案 quote.txt 的內容。此示例模擬了 **cat** 命令。

[jerry]$ sed '' quote.txt

執行上述程式碼時,將產生以下結果。

There is only one thing that makes a dream impossible to achieve: the fear of failure. 

在上面的示例中,quote.txt 是輸入檔名,在其前面有一對單引號,表示 SED 命令。讓我們來揭開這個操作的神秘面紗。

首先,SED 從輸入檔案 quote.txt 讀取一行並將其儲存在其模式緩衝區中。然後它在模式緩衝區上應用 SED 命令。在我們的例子中,沒有 SED 命令,因此沒有對模式緩衝區執行任何操作。最後,它刪除並列印模式緩衝區的內容到標準輸出。是不是很簡單?

在以下示例中,SED 接受來自標準輸入流的輸入。

[jerry]$ sed '' 

執行上述程式碼時,將產生以下結果。

There is only one thing that makes a dream impossible to achieve: the fear of failure. 
There is only one thing that makes a dream impossible to achieve: the fear of failure.

這裡,第一行透過鍵盤輸入,第二行是 SED 生成的輸出。要退出 SED 會話,請按 ctrl-D (^D)。

流編輯器 - 基本語法

本章介紹了 SED 支援的基本命令及其命令列語法。SED 可以以下兩種形式呼叫

sed [-n] [-e] 'command(s)' files 
sed [-n] -f scriptfile files

第一種形式允許在命令列中指定命令,並將它們括在單引號中。後者允許指定包含 SED 命令的指令碼檔案。但是,我們可以多次將這兩種形式結合使用。SED 提供各種命令列選項來控制其行為。

讓我們看看如何指定多個 SED 命令。SED 提供 **delete** 命令來刪除某些行。讓我們刪除第 1、2 和第 5 行。目前,忽略 delete 命令的所有細節。我們將在後面討論更多關於 delete 命令的內容。

首先,使用 **cat** 命令顯示檔案內容。

[jerry]$ cat books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

現在指示 SED 只刪除某些行。這裡,為了刪除三行,我們使用 -e 選項指定了三個單獨的命令。

[jerry]$ sed -e '1d' -e '2d' -e '5d' books.txt 

執行上述程式碼後,你將得到以下結果

3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
6) A Game of Thrones, George R. R. Martin, 864 

此外,我們可以在一個文字檔案中編寫多個 SED 命令,並將該文字檔案作為引數提供給 SED。SED 可以對模式緩衝區應用每個命令。以下示例說明了 SED 的第二種形式。

首先,建立一個包含 SED 命令的文字檔案。為了便於理解,讓我們使用相同的 SED 命令。

[jerry]$ echo -e "1d\n2d\n5d" > commands.txt 
[jerry]$ cat commands.txt

執行上述程式碼後,你將得到以下結果

1d 
2d 
5d 

現在指示 SED 從文字檔案讀取命令。這裡,我們實現了與上面示例中相同的輸出。

[jerry]$ sed -f commands.txt books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
6) A Game of Thrones,George R. R. Martin, 864 

標準選項

SED 支援以下標準選項

  • -n: 預設列印模式緩衝區。例如,以下 SED 命令不顯示任何輸出

  • [jerry]$ sed -n '' quote.txt 
    
  • -e: 下一個引數是一個編輯命令。這裡,尖括號表示必填引數。透過使用此選項,我們可以指定多個命令。讓我們將每一行列印兩次

  • [jerry]$ sed -e '' -e 'p' quote.txt
    

執行上述程式碼後,你將得到以下結果

There is only one thing that makes a dream impossible to achieve: the fear of failure. 
There is only one thing that makes a dream impossible to achieve: the fear of failure. 
 - Paulo Coelho, The Alchemist 
 - Paulo Coelho, The Alchemist
  • -f: 下一個引數是一個包含編輯命令的檔案。尖括號表示必填引數。在以下示例中,我們透過檔案指定 print 命令

[jerry]$ echo "p" > commands 
[jerry]$ sed -n -f commands quote.txt

執行上述程式碼後,你將得到以下結果

There is only one thing that makes a dream impossible to achieve: the fear of failure. 
 - Paulo Coelho, The Alchemist

GNU 特定選項

讓我們快速瀏覽一下 GNU 特定的 SED 選項。請注意,這些選項是 GNU 特定的;可能不受其他 SED 變體支援。在後面的章節中,我們將更詳細地討論這些選項。

  • -n, --quiet, --silent: 與標準 -n 選項相同。

  • -e script, --expression=script: 與標準 -e 選項相同。

  • -f script-file, --file=script-file: 與標準 -f 選項相同。

  • --follow-symlinks: 如果提供此選項,則 SED 在就地編輯檔案時會跟隨符號連結。

  • -i[SUFFIX], --in-place[=SUFFIX]: 此選項用於就地編輯檔案。如果提供了字尾,它會備份原始檔案,否則它會覆蓋原始檔案。

  • -l N, --line-lenght=N: 此選項將 l 命令的行長度設定為 N 個字元。

  • --posix: 此選項停用所有 GNU 擴充套件。

  • -r, --regexp-extended: 此選項允許使用擴充套件正則表示式而不是基本正則表示式。

  • -u, --unbuffered: 提供此選項時,SED 會從輸入檔案中載入最少的資料並更頻繁地重新整理輸出緩衝區。當你不希望等待輸出時,它在編輯 "tail -f" 的輸出時很有用。

  • -z, --null-data: 預設情況下,SED 透過換行符分隔每一行。如果提供了 NULL-data 選項,它會透過 NULL 字元分隔行。

流編輯器 - 迴圈

與其他程式語言一樣,SED 也提供迴圈和分支功能來控制執行流程。在本章中,我們將進一步探討如何在 SED 中使用迴圈和分支。

SED 中的迴圈類似於 **goto** 語句。SED 可以跳轉到標記為標籤的行並繼續執行其餘命令。在 SED 中,我們可以如下定義 **標籤**

:label 
:start 
:end 
:up

在上面的示例中,冒號 (:) 後面的名稱表示標籤名稱。

要跳轉到特定標籤,我們可以使用 **b** 命令後跟標籤名稱。如果省略標籤名稱,則 SED 將跳轉到 SED 檔案的末尾。

讓我們編寫一個簡單的 SED 指令碼以理解迴圈和分支。在我們的 books.txt 檔案中,有多個書籍標題及其作者的條目。以下示例將書籍標題及其作者姓名組合在一行中,用逗號分隔。然後它搜尋模式 "Paulo"。如果模式匹配,它會在行的前面列印一個連字元 (-),否則它會跳轉到 **Print** 標籤,該標籤列印該行。

[jerry]$ sed -n ' 
h;n;H;x 
s/\n/, / 
/Paulo/!b Print 
s/^/- / 
:Print 
p' books.txt

執行上述程式碼後,你將得到以下結果

A Storm of Swords, George R. R. Martin 
The Two Towers, J. R. R. Tolkien 
- The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
- The Pilgrimage, Paulo Coelho
A Game of Thrones, George R. R. Martin 

乍一看,上面的指令碼可能看起來很神秘。讓我們來揭開這個神秘面紗。

  • 前兩個命令 **h;n;H;x** 和 **s/\n/, /** 很容易理解,它們將書籍標題及其作者用逗號 (,) 分隔組合在一起。

  • 第三個命令僅在模式不匹配時跳轉到標籤 **Print**,否則第四個命令會執行替換。

  • :Print 只是一個標籤名稱,如你所知,p 是列印命令。

為了提高可讀性,每個 SED 命令都放在單獨一行。但是,也可以選擇將所有命令放在一行,如下所示

[jerry]$ sed -n 'h;n;H;x;s/\n/, /;/Paulo/!b Print; s/^/- /; :Print;p' books.txt 

執行上述程式碼後,你將得到以下結果

A Storm of Swords, George R. R. Martin 
The Two Towers, J. R. R. Tolkien 
- The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
- The Pilgrimage, Paulo Coelho 
A Game of Thrones, George R. R. Martin

流編輯器 - 分支

可以使用 t 命令建立分支。t 命令僅在前面的替換命令成功時才跳轉到標籤。讓我們以上一章中的相同示例為例,但現在我們列印四個連字元而不是單個連字元 (-)。以下示例說明了 t 命令的用法。

[jerry]$ sed -n ' 
h;n;H;x 
s/\n/, / 
:Loop 
/Paulo/s/^/-/ 
/----/!t Loop 
p' books.txt 

執行上述程式碼時,將產生以下結果。

A Storm of Swords, George R. R. Martin 
The Two Towers, J. R. R. Tolkien 
----The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
----The Pilgrimage, Paulo Coelho 
A Game of Thrones, George R. R. Martin

在上面的示例中,前兩個命令是不言自明的。第三個命令定義了一個標籤 Loop。第四個命令如果該行包含字串“Paulo”,則在前面新增連字元 (-),並且 t 命令重複此過程,直到該行開頭有四個連字元。

為了提高可讀性,每個 SED 命令都寫在單獨一行。否則,我們可以編寫一個單行 SED,如下所示

[jerry]$ sed -n 'h;n;H;x; s/\n/, /; :Loop;/Paulo/s/^/-/; /----/!t Loop; p' books.txt 

執行上述程式碼時,將產生以下結果。

A Storm of Swords, George R. R. Martin 
The Two Towers, J. R. R. Tolkien 
----The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
----The Pilgrimage, Paulo Coelho 
A Game of Thrones, George R. R. Martin

流編輯器 - 模式緩衝區

我們在任何檔案上執行的基本操作之一就是顯示其內容。為此,我們可以使用 print 命令,它列印模式緩衝區的內容。所以讓我們更多地瞭解模式緩衝區

首先建立一個檔案,其中包含行號、書籍名稱、作者和頁數。在本教程中,我們將使用此檔案。您可以根據自己的方便使用任何文字檔案。我們的文字檔案將如下所示

[jerry]$ vi books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho,288 
6) A Game of Thrones, George R. R. Martin, 864

現在,讓我們列印檔案內容。

[jerry]$ sed 'p' books.txt

執行上述程式碼時,將產生以下結果。

1) A Storm of Swords, George R. R. Martin, 1216 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 
6) A Game of Thrones, George R. R. Martin, 864

您可能想知道為什麼每行都顯示兩次。讓我們找出原因。

您還記得 SED 的工作流程嗎?預設情況下,SED 會列印模式緩衝區的內容。此外,我們在命令部分顯式地包含了一個 print 命令。因此,每行都列印了兩次。但不用擔心。SED 有 -n 選項可以抑制模式緩衝區的預設列印。以下命令說明了這一點。

[jerry]$ sed -n 'p' books.txt 

執行上述程式碼時,將產生以下結果。

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

恭喜!我們得到了預期的結果。預設情況下,SED 對所有行進行操作。但是,我們可以強制 SED 僅對某些行進行操作。例如,在下面的示例中,SED 僅對第 3 行進行操作。在此示例中,我們在 SED 命令之前指定了一個地址範圍。

[jerry]$ sed -n '3p' books.txt 

執行上述程式碼時,將產生以下結果。

3) The Alchemist, Paulo Coelho, 197 

此外,我們還可以指示 SED 僅列印某些行。例如,以下程式碼列印第 2 行到第 5 行的所有行。在這裡,我們使用了逗號 (,) 運算子來指定地址範圍。

[jerry]$ sed -n '2,5 p' books.txt 

執行上述程式碼時,將產生以下結果。

2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288

還有一個特殊字元美元符號 ($),它表示檔案的最後一行。所以讓我們列印檔案的最後一行。

[jerry]$ sed -n '$ p' books.txt 

執行上述程式碼時,將產生以下結果。

6) A Game of Thrones, George R. R. Martin, 864 

但是我們也可以使用美元符號 ($) 來指定地址範圍。以下示例列印從第 3 行到最後一行。

[jerry]$ sed -n '3,$ p' books.txt 

執行上述程式碼時,將產生以下結果。

3) The Alchemist, Paulo Coelho, 197 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 5) The Pilgrimage, Paulo Coelho, 288 6) A Game of Thrones, George R. R. Martin, 864 

我們學習瞭如何使用逗號 (,) 運算子指定地址範圍。SED 支援另外兩個可用於指定地址範圍的運算子。第一個是加號 (+) 運算子,它可以與逗號 (,) 運算子一起使用。例如,M, +n 將列印從行號 M 開始的接下來的 n 行。聽起來很困惑?讓我們用一個簡單的例子來檢查一下。以下示例列印從行號 2 開始的接下來的 4 行。

[jerry]$ sed -n '2,+4 p' books.txt 

執行上述程式碼時,將產生以下結果。

2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

或者,我們也可以使用波浪號 (~) 運算子指定地址範圍。它使用 M~n 格式。它表示 SED 應該從行號 M 開始並處理每第 n 行。例如,50~5 匹配行號 50、55、60、65 等。讓我們僅列印檔案中的奇數行。

[jerry]$ sed -n '1~2 p' books.txt 

執行上述程式碼時,將產生以下結果。

1) A Storm of Swords, George R. R. Martin, 1216 
3) The Alchemist, Paulo Coelho, 197 
5) The Pilgrimage, Paulo Coelho, 288

以下程式碼僅列印檔案中的偶數行。

[jerry]$ sed -n '2~2 p' books.txt 

執行上述程式碼時,將產生以下結果。

2) The Two Towers, J. R. R. Tolkien, 352 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
6) A Game of Thrones, George R. R. Martin, 864 

流編輯器 - 模式範圍

在上一章中,我們學習了 SED 如何處理地址範圍。本章介紹 SED 如何處理模式範圍。模式範圍可以是簡單的文字或複雜的正則表示式。讓我們舉個例子。以下示例列印 Paulo Coelho 作者的所有書籍。

[jerry]$ sed -n '/Paulo/ p' books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, Paulo Coelho, 197 
5) The Pilgrimage, Paulo Coelho, 288

在上面的示例中,SED 對每一行進行操作,並且僅列印與字串 Paulo 匹配的行。

我們還可以將模式範圍與地址範圍結合起來。以下示例列印從“鍊金術士”的第一次匹配開始到第五行的行。

[jerry]$ sed -n '/Alchemist/, 5 p' books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288

我們可以使用美元符號 ($) 列印找到模式的第一次出現後的所有行。以下示例查詢模式 The 的第一次出現,並立即列印檔案中剩餘的行

[jerry]$ sed -n '/The/,$ p' books.txt

執行上述程式碼後,你將得到以下結果

2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

我們還可以使用逗號 (,) 運算子指定多個模式範圍。以下示例列印“Two”和“Pilgrimage”模式之間存在的所有行。

[jerry]$ sed -n '/Two/, /Pilgrimage/ p' books.txt 

執行上述程式碼後,你將得到以下結果

2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288

此外,我們可以在模式範圍內使用加號 (+) 運算子。以下示例查詢模式 Two 的第一次出現,並列印其後的接下來的 4 行。

[jerry]$ sed -n '/Two/, +4 p' books.txt

執行上述程式碼後,你將得到以下結果

2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

我們在這裡只提供了一些示例,以幫助您熟悉 SED。您始終可以透過自己嘗試一些示例來了解更多資訊。

流編輯器 - 基本命令

本章描述了幾個有用的 SED 命令。

刪除命令

SED 提供各種命令來操作文字。讓我們首先了解一下 delete 命令。以下是執行刪除命令的方法

[address1[,address2]]d 

address1address2 分別是起始和結束地址,可以是行號或模式字串。這兩個地址都是可選引數。

顧名思義,刪除命令用於執行刪除操作,並且由於 SED 對行進行操作,因此我們可以說此命令用於刪除行。請注意,刪除命令僅從模式緩衝區中刪除行;該行不會發送到輸出流,並且原始檔案保持不變。以下示例說明了這一點。

[jerry]$ sed 'd' books.txt 

但是輸出在哪裡?如果沒有提供行地址,則 SED 預設情況下會對每一行進行操作。因此,它會從模式緩衝區中刪除所有行。這就是為什麼該命令不會在標準輸出上列印任何內容的原因。

讓我們指示 SED 僅對某些行進行操作。以下示例僅刪除第 4 行。

[jerry]$ sed '4d' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

此外,SED 還接受使用逗號 (,) 的地址範圍。我們可以指示 SED 刪除 N1 到 N2 行。例如,以下示例刪除第 2 行到第 4 行的所有行。

[jerry]$ sed '2, 4 d' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

SED 的地址範圍不僅限於數字。我們還可以將模式指定為地址。以下示例刪除 Paulo Coelho 作者的所有書籍。

[jerry]$ sed '/Paulo Coelho/d' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
6) A Game of Thrones, George R. R. Martin, 864 

我們還可以使用文字模式指定地址範圍。以下示例刪除“Storm”和“Fellowship”模式之間的所有行。

[jerry]$ sed '/Storm/,/Fellowship/d' books.txt  
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

除此之外,我們還可以將美元符號 ($)、加號 (+) 和波浪號 (~) 運算子與 SED 一起使用。

寫入命令

我們在任何檔案上執行的重要操作之一是備份,即我們建立檔案的另一個副本。SED 提供 write 命令將模式緩衝區的內容儲存到檔案中。以下是 write 命令的語法,它類似於 delete 命令。

[address1[,address2]]w file 

這裡,address1address2 分別是起始和結束地址,可以是行號或模式字串。這兩個地址都是可選引數。

在上述語法中,w 指的是 write 命令,file 是您儲存內容的檔名。請注意 file 引數。當提供檔名時,如果檔案不存在,則 SED 會動態建立該檔案,如果檔案已存在,則會覆蓋該檔案。

讓我們使用 SED 建立檔案的精確副本。請注意,wfile 之間必須恰好有一個空格。

[jerry]$ sed -n 'w books.bak' books.txt 

我們建立了另一個名為 books.bak 的檔案。現在驗證這兩個檔案是否具有相同的內容。

[jerry]$ diff books.txt books.bak  
[jerry]$ echo $?

執行上述程式碼後,你將得到以下結果

0

您可以假設 cp 命令執行完全相同的功能。是的!cp 命令執行相同的功能,但 SED 是一個成熟的實用程式。它允許建立一個僅包含原始檔中某些行的檔案。讓我們將偶數行儲存到另一個檔案中。

[jerry]$ sed -n '2~2 w junk.txt' books.txt  
[jerry]$ cat junk.txt 

執行上述程式碼後,你將得到以下結果

2) The Two Towers, J. R. R. Tolkien, 352 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
6) A Game of Thrones, George R. R. Martin, 864 

您也可以將逗號 (,)、美元符號 ($) 和加號 (+) 運算子與 write 命令一起使用。

除此之外,SED 還支援模式匹配與 write 命令。假設您想將每個作者的所有書籍儲存到一個單獨的檔案中。一種無聊且冗長的方式是手動執行此操作,而更智慧的方式是使用 SED。

[jerry]$ sed -n -e '/Martin/ w Martin.txt' -e '/Paulo/ w Paulo.txt' -e '/Tolkien/ w 
Tolkien.txt' books.txt 

在上面的示例中,我們正在將每一行與模式進行匹配,並將匹配的行儲存到特定檔案中。這非常簡單。為了指定多個命令,我們使用了 SED 命令的 -e 開關。現在讓我們看看每個檔案包含什麼內容

[jerry]$ cat Martin.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
6) A Game of Thrones, George R. R. Martin, 864

讓我們顯示檔案內容。

[jerry]$ cat Paulo.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, Paulo Coelho, 197 
5) The Pilgrimage, Paulo Coelho, 288 

讓我們顯示檔案內容。

[jerry]$ cat Tolkien.txt

執行上述程式碼後,你將得到以下結果

2) The Two Towers, J. R. R. Tolkien, 352 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 

太棒了!我們得到了預期的結果。SED 確實是一個很棒的實用程式。

追加命令

任何文字編輯器最有用的操作之一就是提供追加功能。SED 透過其 append 命令支援此操作。以下是 append 的語法

[address]a\ 
Append text 

讓我們在行號 4 之後追加一個新的書籍條目。以下示例顯示瞭如何執行此操作

[jerry]$ sed '4 a 7) Adultry, Paulo Coelho, 234' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
7) Adultry, Paulo Coelho, 234 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

在命令部分,4 表示行號,a 是 append 命令,其餘部分是要追加的文字。

讓我們在檔案的末尾插入一行文字。為此,請使用 $ 作為地址。以下示例說明了這一點

[jerry]$ sed '$ a 7) Adultry, Paulo Coelho, 234' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 
7) Adultry, Paulo Coelho, 234 

除了行號之外,我們還可以使用文字模式指定地址。例如,以下示例在匹配字串 The Alchemist 後追加文字。

[jerry]$ sed '/The Alchemist/ a 7) Adultry, Paulo Coelho, 234' books.txt  

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
7) Adultry, Paulo Coelho, 234 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

請注意,如果有多個模式匹配,則會在每次匹配後追加文字。以下示例說明了這種情況。

[jerry]$ sed '/The/ a 7) Adultry, Paulo Coelho, 234' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
7) Adultry, Paulo Coelho, 234 
3) The Alchemist, Paulo Coelho, 197 
7) Adultry, Paulo Coelho, 234 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
7) Adultry, Paulo Coelho, 234 
5) The Pilgrimage, Paulo Coelho, 288 
7) Adultry, Paulo Coelho, 234 
6) A Game of Thrones, George R. R. Martin, 864 

更改命令

SED 提供 changereplace 命令,用 c 表示。此命令有助於用新文字替換現有行。當提供行範圍時,所有行都將作為一個組被替換為單個文字行。以下是更改命令的語法

[address1[,address2]]c\ 
Replace text

讓我們用其他一些文字替換第三行。

[jerry]$ sed '3 c 3) Adultry, Paulo Coelho, 324' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) Adultry, Paulo Coelho, 324 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

SED 也接受模式作為地址。在下面的示例中,當模式匹配成功時,替換一行。

[jerry]$ sed '/The Alchemist/ c 3) Adultry, Paulo Coelho, 324' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) Adultry, Paulo Coelho, 324 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

SED 還允許用一行替換多行。下面的示例刪除第四行到第六行,並用新文字替換它們。

[jerry]$ sed '4, 6 c 4) Adultry, Paulo Coelho, 324' books.txt  

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) Adultry, Paulo Coelho, 324

插入命令

插入命令的工作方式與追加命令非常相似。唯一的區別在於它在特定位置之前插入一行。下面給出的是插入命令的語法

[address]i\ 
Insert text 

讓我們用一些例子來理解插入命令。以下命令在第四行之前插入一個新條目。

[jerry]$ sed '4 i 7) Adultry, Paulo Coelho, 324' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
7) Adultry, Paulo Coelho, 324 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

在上面的示例中,4 是位置編號,i 表示插入命令,其餘部分是要插入的文字。

要在檔案開頭插入文字,請將行地址提供為1。以下命令說明了這一點

[jerry]$ sed '1 i 7) Adultry, Paulo Coelho, 324' books.txt

執行上述程式碼後,你將得到以下結果

7) Adultry, Paulo Coelho, 324 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

此外,我們可以插入多行。以下命令在最後一行之前插入兩行。

[jerry]$ sed '$ i 7) Adultry, Paulo Coelho, 324

執行上述程式碼後,你將得到以下結果

8) Eleven Minutes, Paulo Coelho, 304' books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage,Paulo Coelho, 288 
7) Adultry, Paulo Coelho, 324 
8) Eleven Minutes, Paulo Coelho, 304 
6) A Game of Thrones, George R. R. Martin, 864

請注意,要插入的條目在單獨的行上輸入,並以反斜槓 (\) 字元分隔。

轉換命令

SED 提供了一個轉換字元的命令,它表示為y。它按位置轉換字元。下面給出的是轉換命令的語法

[address1[,address2]]y/list-1/list-2/

請注意,轉換基於字元從列表 1中的位置到列表 2中相同位置的字元,並且兩個列表都必須是顯式字元列表。不支援正則表示式和字元類。此外,列表 1列表 2的大小必須相同。

以下示例將阿拉伯數字轉換為羅馬數字。

[jerry]$ echo "1 5 15 20" | sed 'y/151520/IVXVXX/' 

執行上述程式碼後,你將得到以下結果

I V IV XX 

l 命令

僅透過檢視它們,你能區分空格分隔的單詞和僅由製表符分隔的單詞嗎?當然不能。但是 SED 可以為你做到這一點。SED 使用l命令顯示文字中的隱藏字元。例如,製表符用\t表示,行尾用$字元表示。下面給出的是l命令的語法。

[address1[,address2]]l 
[address1[,address2]]l [len] 

讓我們建立一個包含製表符的檔案進行演示。為簡單起見,我們將使用相同的檔案,只是用製表符替換空格。等等!但是如何做到這一點——透過在文字編輯器中開啟檔案並將每個空格替換為製表符?當然不是!我們可以利用 SED 命令來實現這一點。

[jerry]$ sed 's/ /\t/g' books.txt > junk.txt 

現在讓我們使用l命令顯示隱藏字元

[jerry]$ sed -n 'l' junk.txt

執行上述程式碼後,你將得到以下結果

1)\tA\tStorm\tof\tSwords,George\tR.\tR.\tMartin,1216$ 
2)\tThe\tTwo\tTowers,J.\tR.\tR.\tTolkien,352$ 
3)\tThe\tAlchemist,Paulo\tCoelho,197$ 
4)\tThe\tFellowship\tof\tthe\tRing,J.\tR.\tR.\tTolkien,432$ 
5)\tThe\tPilgrimage,Paulo\tCoelho,288$ 
6)\tA\tGame\tof\tThrones,George\tR.\tR.\tMartin\t,864$

與其他 SED 命令一樣,它也接受行號和模式作為地址。您可以自己嘗試。

讓我們仔細看看 SED 的另一個有趣功能。我們可以指示 SED 在特定數量的字元後執行換行。以下示例在 25 個字元後換行。

[jerry]$ sed -n 'l 25' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords,Geo\ 
rge R. R. Martin,1216$ 
2) The Two Towers,J. R. \ 
R. Tolkien,352$ 
3) The Alchemist,Paulo C\ 
oelho,197$ 
4) The Fellowship of the\ 
 Ring,J. R. R. Tolkien,4\ 
32$ 
5) The Pilgrimage,Paulo \ 
Coelho,288$ 
6) A Game of Thrones,Geo\ 
rge R. R. Martin ,864$

請注意,在上面的示例中,換行限制是在 l 命令之後提供的。在這種情況下,它是 25 個字元。此選項是 GNU 特定的,可能不適用於其他 SED 變體。

換行限制為 0 表示除非有換行符,否則永遠不會換行。以下簡單命令說明了這一點。

[jerry]$ sed -n 'l 0' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords,George R. R. Martin,1216$ 
2) The Two Towers,J. R. R. Tolkien,352$ 
3) The Alchemist,Paulo Coelho,197$ 
4) The Fellowship of the Ring,J. R. R. Tolkien,432$ 
5) The Pilgrimage,Paulo Coelho,288$ 
6) A Game of Thrones,George R. R. Martin,864$ 

退出命令

退出命令指示 SED 退出當前執行流程。它由q命令表示。下面給出的是退出命令的語法

[address]q 
[address]q [value]

請注意,退出命令不接受地址範圍,它只支援單個地址。預設情況下,SED 遵循讀取、執行和重複的工作流程;但是當遇到退出命令時,它只是停止當前執行。

讓我們列印檔案中的前 3 行。

[jerry]$ sed '3 q' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197

除了行號之外,我們還可以使用文字模式。以下命令在模式匹配成功時退出。

[jerry]$ sed '/The Alchemist/ q' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197

除此之外,SED 還可以接受一個,該值可用作退出狀態。以下命令將其退出狀態顯示為 100。

[jerry]$ sed '/The Alchemist/ q 100' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197

現在讓我們驗證退出狀態。

[jerry]$ echo $? 

執行上述程式碼後,你將得到以下結果

100

讀取命令

我們可以指示 SED 讀取檔案的內容並在特定條件匹配時顯示它們。該命令由字母r表示。下面給出的是讀取命令的語法。

[address]r file

請注意,r命令和檔名之間必須恰好有一個空格。

讓我們用一個簡單的例子來理解它。建立一個名為junk.txt的示例檔案。

[jerry]$ echo "This is junk text." > junk.txt 

以下命令指示 SED 讀取junk.txt的內容並在第三行之後插入它們。

[jerry]$ sed '3 r junk.txt' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
This is junk text. 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

在上面的示例中,3 表示行地址,r是命令名稱,junk.txt是要顯示其內容的檔名。此外,GNU SED 還接受地址範圍。例如,以下命令在第三、第四和第五行之後插入junk.txt的內容。

[jerry]$ sed '3, 5 r junk.txt' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
This is junk text. 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
This is junk text. 
5) The Pilgrimage, Paulo Coelho, 288 
This is junk text. 
6) A Game of Thrones, George R. R. Martin, 864

與其他 SED 命令一樣,讀取命令也接受模式作為地址。例如,以下命令在模式匹配成功時插入junk.txt的內容。

[jerry]$ sed '/Paulo/ r junk.txt' books.txt  

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
This is junk text. 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
This is junk text. 
6) A Game of Thrones, George R. R. Martin, 864 

執行命令

我們可以使用執行命令從 SED 執行外部命令。它由e表示。下面給出的是執行命令的語法。

[address1[,address2]]e [command]

讓我們用一個簡單的例子來說明執行命令。以下 SED 命令在第三行之前執行 UNIXdate命令。

[jerry]$ sed '3 e date' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
Sun Sep  7 18:04:49 IST 2014 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

與其他命令一樣,它也接受模式作為地址。例如,以下示例在模式匹配成功時執行date命令。請注意,在每次模式匹配之後,首先執行命令,然後顯示模式緩衝區的內容。

[jerry]$ sed '/Paulo/ e date' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
Sun Sep  7 18:06:04 IST 2014 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
Sun Sep  7 18:06:04 IST 2014 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

如果你仔細觀察e命令的語法,你會注意到命令是可選的。當e後面沒有提供命令時,它會將模式緩衝區的內容視為外部命令。為了說明這一點,讓我們建立一個包含一些簡單命令的commands.txt檔案。

[jerry]$ echo -e "date\ncal\nuname" > commands.txt 
[jerry]$ cat commands.txt

執行上述程式碼後,你將得到以下結果

date 
cal 
uname

檔案中的命令是不言自明的。在e後面沒有命令的情況下,SED 會依次執行所有這些命令。以下簡單示例說明了這一點。

[jerry]$ sed 'e' commands.txt 

執行上述程式碼後,你將得到以下結果

Sun Sep  7 18:14:20 IST 2014 
   September 2014      
Su Mo Tu We Th Fr Sa   
    1  2  3  4  5  6   
 7  8  9 10 11 12 13   
14 15 16 17 18 19 20   
21 22 23 24 25 26 27   
28 29 30               
                       
Linux 

與其他 SED 命令一樣,執行命令也接受所有有效的地址範圍。

其他命令

預設情況下,SED 對單行進行操作,但它也可以對多行進行操作。多行命令用大寫字母表示。例如,與n命令不同,N命令不會清除和列印模式空間。相反,它在當前模式空間的末尾新增一個換行符 (\n),並將輸入檔案中的下一行追加到當前模式空間,並透過執行其餘的 SED 命令繼續 SED 的標準流程。下面給出的是N命令的語法。

[address1[,address2]]N

讓我們列印書籍標題及其相應作者的逗號分隔列表。以下示例說明了這一點。

[jerry]$ sed 'N; s/\n/, /g' books.txt 

執行上述程式碼後,你將得到以下結果

A Storm of Swords, George R. R. Martin 
The Two Towers, J. R. R. Tolkien 
The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
The Pilgrimage, Paulo Coelho 
A Game of Thrones, George R. R. Martin

讓我們瞭解上面的示例是如何工作的。N命令將第一行,即A Storm of Swords讀入模式緩衝區,並追加\n後跟下一行。模式空間現在包含A Storm of Swords\nGeorge R. R. Martin。在下一步中,我們將換行符替換為逗號。

p命令一樣,我們有一個P命令來列印由N命令建立的多行模式空間的第一部分(直到嵌入的換行符)。下面給出的是P命令的語法,它類似於p命令。

[address1[,address2]]P 

在前面的示例中,我們看到N命令建立了一個換行符分隔的書籍標題及其作者列表。讓我們只打印它的第一部分,即只有書籍的標題。以下命令說明了這一點。

[jerry]$ sed -n 'N;P' books.txt

執行上述程式碼後,你將得到以下結果

A Storm of Swords 
The Two Towers 
The Alchemist 
The Fellowship of the Ring 
The Pilgrimage 
A Game of Thrones

請注意,在沒有N的情況下,它的行為與p命令相同。以下簡單命令說明了這種情況。

[jerry]$ sed -n 'P' books.txt

執行上述程式碼後,你將得到以下結果

A Storm of Swords 
George R. R. Martin 
The Two Towers 
J. R. R. Tolkien 
The Alchemist 
Paulo Coelho 
The Fellowship of the Ring 
J. R. R. Tolkien 
The Pilgrimage 
Paulo Coelho 
A Game of Thrones 
George R. R. Martin

除此之外,SED 還提供了一個v命令來檢查版本。如果提供的版本大於已安裝的 SED 版本,則命令執行失敗。請注意,此選項是 GNU 特定的,可能不適用於其他 SED 變體。下面給出的是v命令的語法。

[address1[,address2]]v [version]

首先,找出當前的 SED 版本。

[jerry]$ sed --version 

執行上述程式碼後,你將得到以下結果

sed (GNU sed) 4.2.2 

在下面的示例中,SED 版本大於版本 4.2.2,因此 SED 命令中止其執行。

[jerry]$ sed 'v 4.2.3' books.txt 

執行上述程式碼後,你將得到以下結果

sed: -e expression #1, char 7: expected newer version of sed

但是,如果提供的版本小於或等於版本 4.2.2,則命令按預期工作。

[jerry]$ sed 'v 4.2.2' books.txt

執行上述程式碼後,你將得到以下結果

A Storm of Swords 
George R. R. Martin 
The Two Towers 
J. R. R. Tolkien 
The Alchemist 
Paulo Coelho 
The Fellowship of the Ring 
J. R. R. Tolkien 
The Pilgrimage 
Paulo Coelho 
A Game of Thrones George R. R. Martin

流編輯器 - 特殊字元

SED 提供了兩個被視為命令的特殊字元。本章說明了這兩個特殊字元的用法。

= 命令

“=”命令處理行號。下面給出的是“=”命令的語法

[/pattern/]= 
[address1[,address2]]=

“=”命令將行號及其內容寫入標準輸出流。以下示例說明了這一點。

[jerry]$ sed '=' books.txt 

執行上述程式碼後,你將得到以下結果

1 
1) A Storm of Swords, George R. R. Martin, 1216 
2 
2) The Two Towers, J. R. R. Tolkien, 352 
3 
3) The Alchemist, Paulo Coelho, 197 
4 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5 
5) The Pilgrimage, Paulo Coelho, 288 
6 
6) A Game of Thrones, George R. R. Martin, 864

讓我們列印前四行的行號和內容。以下命令列印帶有行號的前四行,其餘的行不帶行號。

[jerry]$ sed '1, 4=' books.txt 

執行上述程式碼後,你將得到以下結果

1 
1) A Storm of Swords, George R. R. Martin, 1216 
2 
2) The Two Towers, J. R. R. Tolkien, 352 
3 
3) The Alchemist, Paulo Coelho, 197 
4 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

此外,我們可以指示 SED 在模式匹配成功時列印行號。以下示例列印包含模式“Paulo”的行號。

[jerry]$ sed '/Paulo/ =' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

你能猜出以下 SED 命令的功能嗎?

[jerry]$ sed -n '$ =' books.txt

執行上述程式碼後,你將得到以下結果

6 

是的,你答對了。它計算檔案中存在的總行數。讓我們揭開程式碼的神秘面紗。在命令部分,我們使用了“$ =”,它列印最後一行及其內容的行號。但我們也提供了-n標誌,它抑制了模式緩衝區的預設列印。因此,只顯示最後一行號。

& 命令

SED 支援特殊字元&。每當模式匹配成功時,此特殊字元都會儲存匹配的模式。它通常與替換命令一起使用。讓我們看看如何利用這個高效的功能。

book.txt 檔案中的每一行都編號。讓我們在每行的開頭新增Book number字樣。以下示例說明了這一點。

[jerry]$ sed 's/[[:digit:]]/Book number &/' books.txt

執行上述程式碼後,你將得到以下結果

Book number 1) A Storm of Swords, George R. R. Martin, 1216 
Book number 2) The Two Towers, J. R. R. Tolkien, 352 
Book number 3) The Alchemist, Paulo Coelho, 197 
Book number 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
Book number 5) The Pilgrimage, Paulo Coelho, 288 
Book number 6) A Game of Thrones, George R. R. Martin, 864 

這個例子非常簡單。首先,我們搜尋第一個數字的出現位置,它就是行號(這就是我們使用[[:digit:]]的原因),並且SED會自動將匹配的模式儲存在特殊字元&中。在第二步中,我們在每個匹配模式之前插入單詞Book number,也就是在每一行之前。

讓我們看另一個例子。在book.txt檔案中,最後一個數字表示書籍的頁數。讓我們在前面新增“Pages =”。為此,請查詢數字的最後一次出現,並將其替換為“Pages = &”。這裡,&儲存匹配的模式,即頁碼。

[jerry]$ sed 's/[[:digit:]]*$/Pages = &/' books.txt 

執行上述語法後,您將獲得以下結果。

1) A Storm of Swords, George R. R. Martin, Pages = 1216 
2) The Two Towers, J. R. R. Tolkien, Pages = 352 
3) The Alchemist, Paulo Coelho, Pages = 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, Pages = 432 
5) The Pilgrimage, Paulo Coelho,Pages = 288 
6) A Game of Thrones, George R. R. Martin, Pages = 864 

目前,只需記住[[:digit:]]*$查詢數字的最後一次出現。在“正則表示式”章節中,我們將更深入地探討正則表示式。

流編輯器 - 字串

替換命令

像“查詢和替換”這樣的文字替換操作在任何文字編輯器中都很常見。在本節中,我們將說明SED如何執行文字替換。下面是替換命令的語法。

[address1[,address2]]s/pattern/replacement/[flags]

這裡,address1address2分別是起始和結束地址,可以是行號或模式字串。這兩個地址都是可選引數。模式是我們想要替換的文字,替換字串用於替換。此外,我們還可以使用SED指定可選標誌。

在books.txt檔案中,我們使用逗號(,)分隔每一列。讓我們使用豎線(|)分隔每一列。為此,請將逗號(,)替換為豎線(|)。

[jerry]$ sed 's/,/ | /' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords | George R. R. Martin, 1216 
2) The Two Towers | J. R. R. Tolkien, 352 
3) The Alchemist | Paulo Coelho, 197 
4) The Fellowship of the Ring | J. R. R. Tolkien, 432 
5) The Pilgrimage | Paulo Coelho, 288 
6) A Game of Thrones | George R. R. Martin, 864 

如果您仔細觀察,只會替換第一個逗號,第二個逗號保持不變。為什麼?一旦模式匹配,SED就會用替換字串替換它並移動到下一行。預設情況下,它只替換第一個匹配項。要替換所有匹配項,請使用全域性標誌(g)與SED,如下所示。

[jerry]$ sed 's/,/ | /g' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords | George R. R. Martin | 1216 
2) The Two Towers | J. R. R. Tolkien | 352 
3) The Alchemist | Paulo Coelho | 197 
4) The Fellowship of the Ring | J. R. R. Tolkien | 432 
5) The Pilgrimage | Paulo Coelho | 288 
6) A Game of Thrones | George R. R. Martin | 864

現在所有逗號(,)都被替換為豎線(|)。

我們可以指示SED僅在模式匹配成功時執行文字替換。以下示例僅當一行包含模式The Pilgrimage時,才將逗號(,)替換為豎線(|)。

[jerry]$ sed '/The Pilgrimage/ s/,/ | /g' books.txt 

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage | Paulo Coelho | 288 
6) A Game of Thrones, George R. R. Martin, 864

除此之外,SED還可以替換模式的特定出現次數。讓我們只用豎線(|)替換逗號(,)的第二個例項。

[jerry]$ sed 's/,/ | /2' books.txt

執行上述程式碼後,你將得到以下結果

1) A Storm of Swords, George R. R. Martin | 1216 
2) The Two Towers, J. R. R. Tolkien | 352 
3) The Alchemist, Paulo Coelho | 197 
4) The Fellowship of the Ring, J. R. R. Tolkien | 432 
5) The Pilgrimage,Paulo Coelho | 288 
6) A Game of Thrones, George R. R. Martin  | 864

在上面的例子中,SED命令末尾(或標誌的位置)的數字表示第二個匹配項。

SED提供了一個有趣的特性。執行替換後,SED提供了一個選項,只顯示已更改的行。為此,SED使用p標誌,表示列印。以下示例僅列出已更改的行。

[jerry]$ sed -n 's/Paulo Coelho/PAULO COELHO/p' books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288 

我們也可以將更改的行儲存在另一個檔案中。要實現此結果,請使用w標誌。以下示例顯示瞭如何操作。

[jerry]$ sed -n 's/Paulo Coelho/PAULO COELHO/w junk.txt' books.txt

我們使用了相同的SED命令。讓我們驗證junk.txt檔案的內容。

[jerry]$ cat junk.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

要執行不區分大小寫的替換,請使用i標誌,表示忽略大小寫。以下示例執行不區分大小寫的替換。

[jerry]$ sed  -n 's/pAuLo CoElHo/PAULO COELHO/pi' books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

到目前為止,我們只使用了斜槓(/)字元作為分隔符,但我們也可以使用豎線(|)、at符號(@)、脫字元(^)、感嘆號(!)作為分隔符。以下示例顯示瞭如何使用其他字元作為分隔符。

假設您需要將路徑/bin/sed替換為/home/jerry/src/sed/sed-4.2.2/sed。因此,您的SED命令如下所示。

[jerry]$ echo "/bin/sed" | sed 's/\/bin\/sed/\/home\/jerry\/src\/sed\/sed-4.2.2\/sed/'

執行上述程式碼後,你將得到以下結果

/home/jerry/src/sed/sed-4.2.2/sed

我們可以使此命令更易讀且易於理解。讓我們使用豎線(|)作為分隔符,並檢視結果。

[jerry]$ echo "/bin/sed" | sed 's|/bin/sed|/home/jerry/src/sed/sed-4.2.2/sed|'

執行上述程式碼後,你將得到以下結果

/home/jerry/src/sed/sed-4.2.2/sed

確實!我們得到了相同的結果,並且語法更易讀。類似地,我們可以使用“at”符號(@)作為分隔符,如下所示。

[jerry]$ echo "/bin/sed" | sed 's@/bin/sed@/home/jerry/src/sed/sed-4.2.2/sed@'

執行上述程式碼後,你將得到以下結果

/home/jerry/src/sed/sed-4.2.2/sed 

除此之外,我們還可以使用脫字元(^)作為分隔符。

[jerry]$ echo "/bin/sed" | sed 's^/bin/sed^/home/jerry/src/sed/sed-4.2.2/sed^'

執行上述程式碼後,你將得到以下結果

/home/jerry/src/sed/sed-4.2.2/sed 

我們還可以使用感嘆號(!)作為分隔符,如下所示。

[jerry]$ echo "/bin/sed" | sed 's!/bin/sed!/home/jerry/src/sed/sed-4.2.2/sed!'

執行上述程式碼後,你將得到以下結果

/home/jerry/src/sed/sed-4.2.2/sed 

通常,反斜槓(/)用作分隔符,但有時使用SED支援的其他分隔符會更方便。

建立子字串

我們學習了強大的替換命令。讓我們看看是否可以從匹配的文字中找到子字串。讓我們透過一個例子來理解如何做到這一點。

讓我們考慮以下文字。

[jerry]$ echo "Three One Two"

假設我們必須將其排列成一個序列。意思是,它應該先列印One,然後是Two,最後是Three。以下單行程式碼可以滿足需求。

echo "Three One Two" | sed 's|\(\w\+\) \(\w\+\) \(\w\+\)|\2 \3 \1|'

請注意,在上面的示例中,豎線(|)用作分隔符。

在SED中,可以使用分組運算子指定子字串,並且必須以跳脫字元為字首,即\(\)

\w是一個正則表示式,匹配任何字母、數字或下劃線,並且“+”用於匹配多個字元。換句話說,正則表示式\(\w\+\)匹配輸入字串中的單個單詞。

在輸入字串中,有三個單詞用空格分隔,因此有三個用空格分隔的正則表示式。第一個正則表示式儲存第一個單詞,即Three,第二個儲存單詞One,第三個儲存單詞Two

這些子字串由\N引用,其中N是子字串編號。因此,\2列印第二個子字串,即One;\3列印第三個子字串,即Two;以及\1列印第一個子字串,即Three

讓我們用逗號(,)分隔這些單詞,並相應地修改正則表示式。

[jerry]$ echo "Three,One,Two" | sed 's|\(\w\+\),\(\w\+\),\(\w\+\)|\2,\3,\1|'

執行上述程式碼後,你將得到以下結果

One,Two,Three

請注意,現在正則表示式中使用逗號(,)代替空格。

字串替換標誌(僅限GNU SED)

在上一節中,我們看到了替換命令的一些示例。GNU SED提供了一些特殊的轉義序列,這些序列可以在替換字串中使用。請注意,這些字串替換標誌是GNU特有的,可能不適用於其他版本的SED。這裡我們將討論字串替換標誌。

  • \L:當在替換字串中指定\L時,它會將\L之後單詞的其餘所有字元都視為小寫字元。例如,字元“ULO”被視為小寫字元。

[jerry]$ sed -n 's/Paulo/PA\LULO/p' books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, PAulo Coelho, 197
5) The Pilgrimage, PAulo Coelho, 288
  • \u:當在替換字串中指定\u時,它會將\u之後的第一個字元視為大寫字元。在下面的示例中,\u用於字元'a'和'o'之前。因此,SED將這些字元視為大寫字母。

[jerry]$ sed -n 's/Paulo/p\uaul\uo/p' books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, pAulO Coelho, 197 
5) The Pilgrimage, pAulO Coelho, 288
  • \U:當在替換字串中指定\U時,它會將\U之後單詞的其餘所有字元都視為大寫字元。

[jerry]$ sed -n 's/Paulo/\Upaulo/p' books.txt 

執行上述程式碼後,你將得到以下結果

3) The Alchemist, PAULO Coelho, 197 
5) The Pilgrimage, PAULO Coelho, 288
  • \E:此標誌應與\L或\U一起使用。它停止由標誌\L或\U啟動的轉換。在下面的示例中,只有第一個單詞被替換為大寫字母。

[jerry]$ sed -n 's/Paulo Coelho/\Upaulo \Ecoelho/p' books.txt

執行上述程式碼後,你將得到以下結果

3) The Alchemist, PAULO coelho, 197 
5) The Pilgrimage, PAULO coelho, 288

流編輯器 - 模式管理

我們已經討論了模式和保持緩衝區的用法。在本章中,我們將進一步探討它們的用法。讓我們討論n命令,它列印模式空間。它將與其他命令結合使用。下面是then命令的語法。

[address1[,address2]]n

讓我們舉個例子。

[jerry]$ sed 'n' books.txt 

執行上述程式碼後,將產生以下結果。

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 

n命令列印模式緩衝區的內容,清除模式緩衝區,將下一行提取到模式緩衝區,並在其上應用命令。

讓我們假設在n之前有三個SED命令,在n之後有兩個SED命令,如下所示。

Sed command #1 
Sed command #2 
Sed command #3 
n command 
Sed command #4 
Sed command #5

在這種情況下,SED在模式緩衝區上應用前三個命令,清除模式緩衝區,將下一行提取到模式緩衝區,然後在其上應用第四和第五個命令。這是一個非常重要的概念。在完全理解它之前,請不要繼續。

保持緩衝區儲存資料,但SED命令不能直接在保持緩衝區上應用。因此,我們需要將保持緩衝區的資料帶入模式緩衝區。SED提供x命令來交換模式和保持緩衝區的內容。以下命令說明了x命令。

讓我們稍微修改一下books.txt檔案。假設該檔案包含書籍標題及其作者姓名。修改後,檔案應如下所示。

[jerry]$ cat books.txt

執行上述程式碼後,你將得到以下結果

A Storm of Swords 
George R. R. Martin 
The Two Towers 
J. R. R. Tolkien 
The Alchemist 
Paulo Coelho 
The Fellowship of the Ring 
J. R. R. Tolkien 
The Pilgrimage 
Paulo Coelho 
A Game of Thrones 
George R. R. Martin 

讓我們交換兩個緩衝區的內容。例如,以下示例僅列印作者姓名。

[jerry]$ sed -n 'x;n;p' books.txt 

執行上述程式碼後,你將得到以下結果

George R. R. Martin 
J. R. R. Tolkien 
Paulo Coelho 
J. R. R. Tolkien 
Paulo Coelho 
George R. R. Martin 

讓我們瞭解此命令的工作原理。

  • 最初,SED將第一行,即A Storm of Swords讀入模式緩衝區。

  • x命令將此行移動到保持緩衝區。

  • n將下一行,即George R. R. Martin提取到模式緩衝區。

  • 控制權傳遞到n後面的命令,該命令列印模式緩衝區的內容。

  • 該過程重複,直到檔案耗盡。

現在讓我們在列印之前交換緩衝區的內容。猜猜會發生什麼?是的,它列印書籍的標題。

[jerry]$ sed -n 'x;n;x;p' books.txt 

執行上述程式碼後,你將得到以下結果

A Storm of Swords 
The Two Towers 
The Alchemist 
The Fellowship of the Ring 
The Pilgrimage 
A Game of Thrones

h命令處理保持緩衝區。它將資料從模式緩衝區複製到保持緩衝區。保持緩衝區中的現有資料會被覆蓋。請注意,h命令不會移動資料,它只會複製資料。因此,複製的資料在模式緩衝區中保持不變。下面是h命令的語法。

[address1[,address2]]h 

以下命令僅列印作者Paulo Coelho的書籍標題。

[jerry]$ sed -n '/Paulo/!h; /Paulo/{x;p}' books.txt 

執行上述程式碼後,你將得到以下結果

The Alchemist 
The Pilgrimage

讓我們瞭解上述命令的工作原理。books.txt的內容遵循特定的格式。第一行是書籍標題,後面跟著書籍的作者。在上面的命令中,“!”用於反轉條件,即僅當模式匹配不成功時,才將行復制到保持緩衝區。花括號{}用於對多個SED命令進行分組。

在命令的第一次傳遞中,SED將第一行,即A Storm of Swords讀入模式緩衝區,並檢查它是否包含模式Paulo。由於模式匹配不成功,因此它將此行復制到保持緩衝區。現在模式緩衝區和保持緩衝區都包含相同的行,即A Storm of Swords。在第二步中,它檢查該行是否包含模式Paulo。由於模式不匹配,因此它不執行任何操作。

在第二次傳遞中,它將下一行George R. R. Martin讀入模式緩衝區並應用相同的步驟。對於接下來的三行,它執行相同操作。在第五次傳遞結束時,兩個緩衝區都包含The Alchemist。在第六次傳遞開始時,它讀取行Paulo Coelho,並且由於模式匹配,因此它不會將此行復制到保持緩衝區。因此,模式緩衝區包含Paulo Coelho,保持緩衝區包含The Alchemist。

此後,它檢查模式緩衝區是否包含模式Paulo。由於模式匹配成功,因此它將模式緩衝區的內容與保持緩衝區的內容交換。現在模式緩衝區包含The Alchemist,保持緩衝區包含Paulo Coelho。最後,它列印模式緩衝區的內容。相同的步驟應用於模式The Pilgrimage。

h 命令會銷燬保持緩衝區中的先前內容。這並不總是可接受的,因為有時我們需要保留內容。為此,SED 提供了H 命令,它透過在末尾新增新行將內容追加到保持緩衝區。hH 命令之間的唯一區別在於,前者會覆蓋保持緩衝區中的資料,而後者會將資料追加到保持緩衝區。其語法與h 命令類似。

[address1[,address2]]H

讓我們再舉一個例子。這次,我們不只列印書籍標題,還要列印作者姓名。以下示例列印書籍標題,後跟作者姓名。

[jerry]$ sed -n '/Paulo/!h; /Paulo/{H;x;p}' books.txt 

執行上述程式碼後,你將得到以下結果

The Alchemist 
Paulo Coelho 
The Pilgrimage
Paulo Coelho

我們學習瞭如何將模式緩衝區的內容複製/追加到保持緩衝區。我們也可以執行反向功能嗎?當然可以!為此,SED 提供了g 命令,該命令將資料從保持緩衝區複製到模式緩衝區。在複製過程中,模式空間中的現有資料會被覆蓋。下面是g 命令的語法。

[address1[,address2]]g

讓我們考慮同一個示例——列印書籍標題及其作者。這次,我們將首先列印作者姓名,然後在下一行列印相應的書籍標題。以下命令列印作者 Paulo Coelho 的姓名,後跟其書籍標題。

[jerry]$ sed -n '/Paulo/!h; /Paulo/{p;g;p}' books.txt 

執行上述程式碼後,你將得到以下結果

Paulo Coelho 
The Alchemist 
Paulo Coelho 
The Pilgrimage

第一個命令保持不變。在第五次傳遞結束時,兩個緩衝區都包含 The Alchemist。在第六次傳遞開始時,它讀取行 Paulo Coelho,並且由於模式匹配,它不會將此行復制到保持緩衝區。因此,模式空間包含 Paulo Coelho,而保持空間包含 The Alchemist。

此後,它檢查模式空間是否包含模式 Paulo。由於模式匹配成功,它首先列印模式空間的內容,即 Paulo Coelho,然後將保持緩衝區複製到模式緩衝區。因此,模式緩衝區和保持緩衝區都包含 The Alchemist。最後,它列印模式緩衝區的內容。相同的步驟應用於模式 The Pilgrimage。

類似地,我們可以將保持緩衝區的內容追加到模式緩衝區。SED 提供了G 命令,它透過在末尾新增新行將內容追加到模式緩衝區。

[address1[,address2]]G

現在讓我們以之前的示例為例,該示例列印作者 Paulo Coelho 的姓名,後跟其書籍標題。要實現相同的結果,請執行以下 SED 命令。

[jerry]$ sed -n '/Paulo/!h; /Paulo/{G;p}' books.txt

執行上述程式碼後,你將得到以下結果

Paulo Coelho 
The Alchemist 
Paulo Coelho 
The Pilgrimage

您能否修改上述示例以顯示書籍標題後跟作者?很簡單,只需在G 命令之前交換緩衝區內容即可。

[jerry]$ sed -n '/Paulo/!h; /Paulo/{x;G;p}' books.txt

執行上述程式碼後,你將得到以下結果

The Alchemist 
Paulo Coelho 
The Pilgrimage 
Paulo Coelho 

流編輯器 - 正則表示式

正是正則表示式使 SED 變得強大而高效。許多複雜的任務都可以用正則表示式來解決。任何命令列專家都知道正則表示式的強大功能。

與許多其他 GNU/Linux 實用程式一樣,SED 也支援正則表示式,通常稱為regex。本章詳細介紹了正則表示式。本章分為三個部分:標準正則表示式、POSIX 正則表示式類和元字元。

標準正則表示式

行首 (^)

在正則表示式術語中,插入符號 (^) 符號匹配行的開頭。以下示例列印所有以模式“The”開頭的行。

[jerry]$ sed -n '/^The/ p' books.txt

執行上述程式碼後,你將得到以下結果

The Two Towers, J. R. R. Tolkien 
The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
The Pilgrimage, Paulo Coelho

行尾 ($)

行尾由美元符號 ($) 表示。以下示例列印以“Coelho”結尾的行。

[jerry]$ sed -n '/Coelho$/ p' books.txt 

執行上述程式碼後,你將得到以下結果

The Alchemist, Paulo Coelho 
The Pilgrimage, Paulo Coelho

單個字元 (.)

點 (.) 匹配除行尾字元之外的任何單個字元。以下示例列印所有以字元“t”結尾的三個字母的單詞。

[jerry]$ echo -e "cat\nbat\nrat\nmat\nbatting\nrats\nmats" | sed -n '/^..t$/p' 

執行上述程式碼後,你將得到以下結果

cat 
bat 
rat 
mat

匹配字元集 ([])

在正則表示式術語中,字元集由方括號 ([]) 表示。它用於匹配多個字元中的一個。以下示例匹配模式“Call”和“Tall”,但不匹配“Ball”。

[jerry]$ echo -e "Call\nTall\nBall" | sed -n '/[CT]all/ p'

執行上述程式碼後,你將得到以下結果

Call 
Tall

排除集 ([^])

在排除集中,插入符號否定方括號中字元的集合。以下示例僅列印“Ball”。

[jerry]$ echo -e "Call\nTall\nBall" | sed -n '/[^CT]all/ p'

執行上述程式碼後,你將得到以下結果

Ball 

字元範圍 ([-])

當提供字元範圍時,正則表示式匹配方括號中指定的範圍內的任何字元。以下示例匹配“Call”和“Tall”,但不匹配“Ball”。

[jerry]$ echo -e "Call\nTall\nBall" | sed -n '/[C-Z]all/ p' 

執行上述程式碼後,你將得到以下結果

Call 
Tall

現在讓我們將範圍修改為“A-P”並觀察結果。

[jerry]$ echo -e "Call\nTall\nBall" | sed -n '/[A-P]all/ p' 

執行上述程式碼後,你將得到以下結果

Call 
Ball

零次或一次出現 (\?)

在 SED 中,問號 (\?) 匹配前一個字元的零次或一次出現。以下示例匹配“Behaviour”和“Behavior”。在這裡,我們使用“\?”將“u”作為可選字元。

[jerry]$ echo -e "Behaviour\nBehavior" | sed -n '/Behaviou\?r/ p' 

執行上述程式碼後,你將得到以下結果

Behaviour 
Behavior

一次或多次出現 (\+)

在 SED 中,加號 (+) 匹配前一個字元的一次或多次出現。以下示例匹配“2”的一次或多次出現。

[jerry]$ echo -e "111\n22\n123\n234\n456\n222"  | sed -n '/2\+/ p'

執行上述程式碼後,你將得到以下結果

22 
123 
234 
222 

零次或多次出現 (*)

星號 (*) 匹配前一個字元的零次或多次出現。以下示例匹配“ca”、“cat”、“catt”等。

[jerry]$ echo -e "ca\ncat" | sed -n '/cat*/ p' 

執行上述程式碼後,你將得到以下結果

ca 
cat 

恰好 N 次出現 {n}

{n} 恰好匹配前一個字元的“n”次出現。以下示例僅列印三位數。但在那之前,您需要建立以下僅包含數字的檔案。

[jerry]$ cat numbers.txt 

執行上述程式碼後,你將得到以下結果

1 
10 
100 
1000 
10000 
100000 
1000000 
10000000 
100000000 
1000000000

讓我們編寫 SED 表示式。

[jerry]$ sed -n '/^[0-9]\{3\}$/ p' numbers.txt 

執行上述程式碼後,你將得到以下結果

100

請注意,花括號對由“\”字元轉義。

至少 n 次出現 {n,}

{n,} 匹配前一個字元的至少“n”次出現。以下示例列印所有大於或等於五位的數字。

[jerry]$ sed -n '/^[0-9]\{5,\}$/ p' numbers.txt

執行上述程式碼後,你將得到以下結果

10000 
100000 
1000000
10000000 
100000000 
1000000000 

M 到 N 次出現 {m, n}

{m, n} 匹配前一個字元的至少“m”次,最多“n”次出現。以下示例列印所有至少有五位數但不多於八位數的數字。

[jerry]$ sed -n '/^[0-9]\{5,8\}$/ p' numbers.txt

執行上述程式碼後,你將得到以下結果

10000 
100000 
1000000 
10000000 

管道 (|)

在 SED 中,管道字元的行為類似於邏輯或運算。它匹配管道兩側的專案。以下示例匹配“str1”或“str3”。

[jerry]$ echo -e "str1\nstr2\nstr3\nstr4" | sed -n '/str\(1\|3\)/ p' 

執行上述程式碼後,你將得到以下結果

str1 
str3

請注意,括號對和管道 (|) 由“\”字元轉義。

跳脫字元

某些特殊字元。例如,換行符由“\n”表示,回車符由“\r”表示,等等。要在常規 ASCII 上下文中使用這些字元,我們必須使用反斜槓 (\) 字元對其進行轉義。本章說明了特殊字元的轉義。

轉義“\”

以下示例匹配模式“\”。

[jerry]$ echo 'str1\str2' | sed -n '/\\/ p'

執行上述程式碼後,你將得到以下結果

str1\str2 

轉義“\n”

以下示例匹配換行符。

[jerry]$ echo 'str1\nstr2' | sed -n '/\\n/ p'

執行上述程式碼後,你將得到以下結果

str1\nstr2

轉義“\r”

以下示例匹配回車符。

[jerry]$ echo 'str1\rstr2' | sed -n '/\\r/ p'

執行上述程式碼後,你將得到以下結果

str1\rstr2

轉義“\dnnn”

這匹配十進位制 ASCII 值為“nnn”的字元。以下示例僅匹配字元“a”。

[jerry]$ echo -e "a\nb\nc" | sed -n '/\d97/ p'

執行上述程式碼後,你將得到以下結果

a

轉義“\onnn”

這匹配八進位制 ASCII 值為“nnn”的字元。以下示例僅匹配字元“b”。

[jerry]$ echo -e "a\nb\nc" | sed -n '/\o142/ p' 

執行上述程式碼後,你將得到以下結果

b 

這匹配十六進位制 ASCII 值為“nnn”的字元。以下示例僅匹配字元“c”。

[jerry]$ echo -e "a\nb\nc" | sed -n '/\x63/ p'

執行上述程式碼後,你將得到以下結果

c

POSIX 正則表示式類

某些保留字具有特殊含義。這些保留字稱為 POSIX 正則表示式類。本節介紹 SED 支援的 POSIX 類。

[:alnum:]

它表示字母數字字元。以下示例僅匹配“One”和“123”,但不匹配製表符。

[jerry]$ echo -e "One\n123\n\t" | sed -n '/[[:alnum:]]/ p'

執行上述程式碼後,你將得到以下結果

One 
123

[:alpha:]

它僅表示字母字元。以下示例僅匹配單詞“One”。

[jerry]$ echo -e "One\n123\n\t" | sed -n '/[[:alpha:]]/ p'

執行上述程式碼後,你將得到以下結果

One 

[:blank:]

它表示空格字元,可以是空格或製表符。以下示例僅匹配製表符。

[jerry]$ echo -e "One\n123\n\t" | sed -n '/[[:space:]]/ p' | cat -vte

執行上述程式碼後,你將得到以下結果

^I$

請注意,命令“cat -vte”用於顯示製表符 (^I)。

[:digit:]

它僅表示十進位制數字。以下示例僅匹配數字“123”。

[jerry]$ echo -e "abc\n123\n\t" | sed -n '/[[:digit:]]/ p' 

執行上述程式碼後,你將得到以下結果

123 

[:lower:]

它僅表示小寫字母。以下示例僅匹配“one”。

[jerry]$ echo -e "one\nTWO\n\t" | sed -n '/[[:lower:]]/ p' 

執行上述程式碼後,你將得到以下結果

one 

[:upper:]

它僅表示大寫字母。以下示例僅匹配“TWO”。

[jerry]$ echo -e "one\nTWO\n\t" | sed -n '/[[:upper:]]/ p'

執行上述程式碼後,你將得到以下結果

TWO

[:punct:]

它表示標點符號,包括非空格或字母數字字元

[jerry]$ echo -e "One,Two\nThree\nFour" | sed -n '/[[:punct:]]/ p'

執行上述程式碼後,你將得到以下結果

One,Two

[:space:]

它表示空格字元。以下示例說明了這一點。

[jerry]$ echo -e "One\n123\f\t" | sed -n '/[[:space:]]/ p' | cat -vte 

執行上述程式碼後,你將得到以下結果

123^L^I$ 

元字元

與傳統正則表示式一樣,SED 也支援元字元。這些是 Perl 樣式的正則表示式。請注意,元字元支援是 GNU SED 特定的,可能不適用於其他 SED 變體。讓我們詳細討論元字元。

詞邊界 (\b)

在正則表示式術語中,“\b”匹配詞邊界。例如,“\bthe\b”匹配“the”,但不匹配“these”、“there”、“they”、“then”等。以下示例說明了這一點。

[jerry]$ echo -e "these\nthe\nthey\nthen" | sed -n '/\bthe\b/ p'

執行上述程式碼後,你將得到以下結果

the

非詞邊界 (\B)

在正則表示式術語中,“\B”匹配非詞邊界。例如,“the\B”匹配“these”和“they”,但不匹配“the”。以下示例說明了這一點。

[jerry]$ echo -e "these\nthe\nthey" | sed -n '/the\B/ p'

執行上述程式碼後,你將得到以下結果

these 
they

單個空格 (\s)

在 SED 中,“\s”表示單個空格字元。以下示例匹配“Line\t1”,但不匹配“Line1”。

[jerry]$ echo -e "Line\t1\nLine2" | sed -n '/Line\s/ p'

執行上述程式碼後,你將得到以下結果

Line 1 

單個非空格 (\S)

在 SED 中,“\S”表示單個空格字元。以下示例匹配“Line2”,但不匹配“Line\t1”。

[jerry]$ echo -e "Line\t1\nLine2" | sed -n '/Line\S/ p' 

執行上述程式碼後,你將得到以下結果

Line2

單個單詞字元 (\w)

在 SED 中,“\w”表示單個單詞字元,即字母字元、數字和下劃線 (_) 。以下示例說明了這一點。

[jerry]$ echo -e "One\n123\n1_2\n&;#" | sed -n '/\w/ p'

執行上述程式碼後,你將得到以下結果

One 
123 
1_2

單個非單詞字元 (\W)

在 SED 中,“\W”表示單個非單詞字元,這與“\w”完全相反。以下示例說明了這一點。

[jerry]$ echo -e "One\n123\n1_2\n&;#" | sed -n '/\W/ p'

執行上述程式碼後,你將得到以下結果

&;#

模式空間的開頭 (\`)

在 SED 中,“\`”表示模式空間的開頭。以下示例僅匹配單詞“One”。

[jerry]$ echo -e "One\nTwo One" | sed -n '/\`One/ p' 

執行上述程式碼後,你將得到以下結果

One

流編輯器 - 有用技巧

SED 是一款非常棒的實用程式,它允許透過多種方式解決問題。這是 UNIX 方式,SED 完美地證明了這一點。GNU/Linux 提供了許多有用的實用程式來執行日常任務。讓我們使用 SED 模擬一些實用程式。有時,我們似乎正在以困難的方式解決一個簡單的問題,但目的只是為了展示 SED 的強大功能。

Cat 命令

在以下示例中,每一行都作為預設工作流程的一部分列印。

[jerry]$ sed '' books.txt 

執行上述程式碼後,你將得到以下結果

A Storm of Swords, George R. R. Martin 
The Two Towers, J. R. R. Tolkien 
The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
The Pilgrimage, Paulo Coelho 
A Game of Thrones, George R. R. Martin 

以下示例使用 print 命令顯示檔案內容。

[jerry]$ sed -n 'p' books.txt 

執行上述程式碼後,你將得到以下結果

A Storm of Swords, George R. R. Martin 
The Two Towers, J. R. R. Tolkien 
The Alchemist, Paulo Coelho 
The Fellowship of the Ring, J. R. R. Tolkien 
The Pilgrimage, Paulo Coelho 
A Game of Thrones, George R. R. Martin

刪除空行

在以下示例中,“^$”表示空行,當模式匹配成功時,空行會被刪除。

[jerry]$ echo -e "Line #1\n\n\nLine #2" | sed '/^$/d'

執行上述程式碼後,你將得到以下結果

Line #1 
Line #2 

類似地,以下示例僅在行非空時列印該行。

[jerry]$ echo -e "Line #1\n\n\nLine #2" | sed -n '/^$/!p'

執行上述程式碼後,你將得到以下結果

Line #1 
Line #2

從 C++ 程式中刪除註釋行

讓我們建立一個示例 C++ 程式。

#include <iostream> 
using namespace std; 

int main(void) 
{ 
   // Displays message on stdout. 
   cout >> "Hello, World !!!" >> endl;  
   return 0; // Return success. 
}

現在使用以下正則表示式刪除註釋。

[jerry]$ sed 's|//.*||g' hello.cpp

執行上述程式碼後,你將得到以下結果

#include <iostream>
using namespace std; 

int main(void) 
{ 
   cout >> "Hello, World !!!" >> endl; 
   return 0;  
} 

在特定行之前添加註釋

以下示例在第 3 到第 5 行之前添加註釋。

[jerry]$ sed '3,5 s/^/#/' hello.sh 

執行上述程式碼後,你將得到以下結果

#!/bin/bash 
#pwd 
#hostname 
#uname -a 
who 
who -r 
lsb_release -a

Wc -l 命令

"wc -l" 命令計算檔案中存在的行數。以下 SED 表示式模擬了相同的功能。

[jerry]$ sed -n '$ =' hello.sh 

執行上述程式碼後,你將得到以下結果

8 

Head 命令

預設情況下,head 命令列印檔案的頭 10 行。讓我們用 SED 模擬相同的行為。

[jerry]$ sed '10 q' books.txt 

執行上述程式碼後,你將得到以下結果

A Storm of Swords 
George R. R. Martin 
The Two Towers 
J. R. R. Tolkien 
The Alchemist 
Paulo Coelho 
The Fellowship of the Ring 
J. R. R. Tolkien 
The Pilgrimage
Paulo Coelho

Tail -1 命令

"tail -1" 列印檔案的最後一行。以下語法顯示了它的模擬。

[jerry]$ echo -e "Line #1\nLine #2" > test.txt 
[jerry]$ cat test.txt

執行上述程式碼後,你將得到以下結果

Line #1 
Line #2 

讓我們編寫 SED 指令碼。

[jerry]$ sed -n '$p' test.txt

執行上述程式碼後,你將得到以下結果

Line #2 

Dos2unix 命令

在 DOS 環境中,換行符由 CR/LF 字元組合表示。以下“dos2unix”命令的模擬將 DOS 換行符轉換為 UNIX 換行符。在 GNU/Linux 中,此字元通常被視為“^M”(控制 M)字元。

[jerry]$ echo -e "Line #1\r\nLine #2\r" > test.txt 
[jerry]$ file test.txt

執行上述程式碼後,你將得到以下結果

test.txt: ASCII text, with CRLF line terminators 

讓我們使用 SED 模擬該命令。

[jerry]$ sed 's/^M$//' test.txt > new.txt   # Press "ctrl+v" followed "ctrl+m" to generate 
"^M" character. 
[jerry]$ file new.txt

執行上述程式碼後,你將得到以下結果

new.txt: ASCII text 

現在讓我們顯示檔案內容。

[jerry]$ cat -vte new.txt 

執行上述程式碼後,你將得到以下結果

Line #1$ 
Line #2$

Unix2dos 命令

類似於“dos2unix”,存在“unix2dos”命令,它將 UNIX 換行符轉換為 DOS 換行符。以下示例顯示了相同的模擬。

[jerry]$ echo -e "Line #1\nLine #2" > test.txt 
[jerry]$ file test.txt 

執行上述程式碼後,你將得到以下結果

test.txt: ASCII text

讓我們使用 SED 模擬該命令。

[jerry]$ sed 's/$/\r/' test.txt  > new.txt 
[jerry]$ file new.txt

執行上述程式碼後,你將得到以下結果

new.txt: ASCII text, with CRLF line terminators

現在讓我們顯示檔案內容。

Now let us display the file contents.

執行上述程式碼後,你將得到以下結果

Line #1^M$ 
Line #2^M$ 

Cat -E 命令

"cat -E" 命令在行尾顯示美元符號 ($) 字元。以下 SED 示例是對其的模擬。

[jerry]$ echo -e "Line #1\nLine #2" > test.txt 
[jerry]$ cat -E test.txt 

執行上述程式碼後,你將得到以下結果

Line #1$ 
Line #2$

讓我們使用 SED 模擬該命令。

[jerry]$ sed 's|$|&$|' test.txt

執行上述程式碼後,你將得到以下結果

Line #1$ 
Line #2$

Cat -ET 命令

"cat -ET" 命令在每行末尾顯示美元符號 ($) 並將 TAB 字元顯示為“^I”。以下示例顯示了使用 SED 模擬“cat -ET”命令。

[jerry]$ echo -e "Line #1\tLine #2" > test.txt 
[jerry]$ cat -ET test.txt

執行上述程式碼後,你將得到以下結果

Line #1^ILine #2$ 

讓我們使用 SED 模擬該命令。

[jerry]$ sed -n 'l' test.txt | sed 'y/\\t/^I/'

執行上述程式碼後,你將得到以下結果

Line #1^ILine #2$ 

Nl 命令

"nl" 命令簡單地對檔案行進行編號。以下 SED 指令碼模擬了此行為。

[jerry]$ echo -e "Line #1\nLine #2" > test.txt 
[jerry]$ sed = test.txt | sed 'N;s/\n/\t/'

執行上述程式碼後,你將得到以下結果

1 Line #1 
2 Line #2

第一個 SED 表示式列印行號及其內容,第二個 SED 表示式合併這兩行並將換行符轉換為 TAB 字元。

Cp 命令

"cp" 命令建立檔案的另一個副本。以下 SED 指令碼模擬了此行為。

[jerry]$ sed -n 'w dup.txt' data.txt 
[jerry]$ diff data.txt dup.txt 
[jerry]$ echo $? 

執行上述程式碼後,你將得到以下結果

0

Expand 命令

"expand" 命令將 TAB 字元轉換為空格。以下程式碼顯示了它的模擬。

[jerry]$ echo -e "One\tTwo\tThree" > test.txt 
[jerry]$ expand test.txt > expand.txt 
[jerry]$ sed 's/\t/     /g' test.txt > new.txt 
[jerry]$ diff new.txt expand.txt  
[jerry]$ echo $? 

執行上述程式碼後,你將得到以下結果

0 

Tee 命令

"tee" 命令將資料轉儲到標準輸出流以及檔案。下面給出了“tee”命令的模擬。

[jerry]$ echo -e "Line #1\nLine #2" | tee test.txt  
Line #1 
Line #2 

讓我們使用 SED 模擬該命令。

[jerry]$ sed -n 'p; w new.txt' test.txt  

執行上述程式碼後,你將得到以下結果

Line #1 
Line #2

Cat -s 命令

UNIX“cat -s”命令抑制重複的空輸出行。以下程式碼顯示了“cat -s”命令的模擬。

[jerry]$ echo -e "Line #1\n\n\n\nLine #2\n\n\nLine #3" > test.txt  
[jerry]$ cat -s test.txt 

執行上述程式碼後,你將得到以下結果

Line #1  
Line #2
Line #3

讓我們使用 SED 模擬該命令。

[jerry]$ sed '1s/^$//p;/./,/^$/!d' test.txt 

執行上述程式碼後,你將得到以下結果

Line #1  
Line #2  
Line #3 

Grep 命令

預設情況下,“grep”命令在模式匹配成功時列印一行。以下程式碼顯示了它的模擬。

[jerry]$ echo -e "Line #1\nLine #2\nLine #3" > test.txt  
[jerry]$ grep "Line #1" test.txt 

執行上述程式碼後,你將得到以下結果

Line #1

讓我們使用 SED 模擬該命令。

[jerry]$ sed -n '/Line #1/p' test.txt 

執行上述程式碼後,你將得到以下結果

Line #1 

Grep -v 命令

預設情況下,“grep -v”命令在模式匹配失敗時列印一行。以下程式碼顯示了它的模擬。

[jerry]$ echo -e "Line #1\nLine #2\nLine #3" > test.txt  
[jerry]$ grep -v "Line #1" test.txt

執行上述程式碼後,你將得到以下結果

Line #2 
Line #3 

讓我們使用 SED 模擬該命令。

[jerry]$ sed -n '/Line #1/!p' test.txt

執行上述程式碼後,你將得到以下結果

Line #2 
Line #3

Tr 命令

"tr" 命令轉換字元。下面給出了它的模擬。

[jerry]$ echo "ABC" | tr "ABC" "abc" 

執行上述程式碼後,你將得到以下結果

abc

讓我們使用 SED 模擬該命令。

[jerry]$ echo "ABC" | sed 'y/ABC/abc/'

執行上述程式碼後,你將得到以下結果

abc
廣告