sed(意為流編輯器,源自英語stream editor」的縮寫)是一個使用簡單緊湊的編程語言來解析和轉換文本Unix實用程序。

sed
編程範型腳本
設計者李·E·麥克馬洪
面市時間1974年,​50年前​(1974
實作語言C
網站 編輯維基數據鏈接
啟發語言
ed
影響語言
Chomski英語Chomski, Perl, AWK

sed由貝爾實驗室李·E·麥克馬洪於1973年至1974年開發, [1] 並且現在大多數操作系統都可以使用。 [2] sed基於交互式編輯器ed(「editor」,1971)和早期qed(「quick editor」,1965-66)的腳本功能。sed是最早支持正則表達式的工具之一,至今仍然用於文本處理,特別是用於替換命令。用於純文本字符串操作和「流編輯」的常用工具還有AWKPerl

歷史

sed是為命令行處理數據文件而構建的早期Unix命令之一,首次出現在Version 7 Unix中 。[3]它很自然地演變成為流行的grep命令的後繼。[4] 最初的動機與grep(g/re/p)的替換類似,因此稱為「g/re/s」。[3] 考慮到這樣的話還會出現針對每個命令的專用程序,例如g/re/d,李·E·麥克馬洪編寫了一個通用的面向行的流編輯器,該編輯器後來成為了sed。[4] sed的語法,特別是把/用於模式匹配,把s///用於替換,起源於sed的前身ed(當時ed很常用)[4] 而且正則表達式語法影響了其他一些語言,特別是ECMAScriptPerl。後來,更強大的語言AWK問世,這些工具相互補充,讓通過shell腳本完成強大的文本處理成為可能。sed和AWK常被認為Perl的祖先和靈感來源,並且影響了Perl的語法和語義,尤其影響了匹配和替換運算符。

GNU sed添加了一些新功能,包括文件的就地編輯 。Super-sed 是sed的擴展版本,包含與Perl兼容的正則表達式。sed的另一變體minised ,最初埃里克·雷蒙把4.1BSD sed通過逆向工程寫成,目前由René Rebe維護。在GNU計劃基於新的GNU正則表達式庫編寫了新版本的sed之前,GNU計劃一直使用minised。當前minised包含一些BSD sed的擴展,但不像GNU sed那樣功能豐富。它的優點是速度快,占用的內存少。它用於嵌入式系統,是Minix提供的sed版本。

工作模式

sed是一個面向行的文本處理實用程序:它從輸入流或文件中逐行讀取文本到一個稱為模式空間 的內部緩衝區。每讀一行開始一個循環 。對於模式空間,sed會應用sed腳本 指定的一個或多個操作。sed實現了一種編程語言,其中包含大約25個指定文本操作的命令 。對於每個輸入行,在運行腳本之後,sed通常輸出模式空間(由腳本修改的行),然後從下一行再次開始循環。其他腳本結束行為可通過sed選項和腳本命令獲得,例如d刪除模式空間,q退出,N立即將下一行添加到模式空間,等等。因此,sed腳本對應於循環體,循環體遍歷流的行,其中循環本身和循環變量(當前行號)是隱式的並由sed維護。

可以在命令行上指定sed腳本( -e選項),也可以從單獨的文件中讀取( -f選項)。sed腳本中的命令可以採用行號或正則表達式的作為地址 。該地址確定決定命令何時運行。例如,2d將僅在第二個輸入行上運行d(刪除)命令(打印除第二個輸入行之外的所有行),而/^ /d將刪除以空格開頭的所有行。一些單獨的特殊緩衝區,即保持空間,可以由幾個sed命令使用,用於在循環之間保持和累積文本。sed的命令語言只有兩個變量(「保持空間」和「模式空間」)和類似GOTO的分支功能;然而,這種語言是圖靈完備的,[5][6] 用深奧sed腳本甚至寫得出推箱子打磚塊[7]國際象棋[8]俄羅斯方塊[9]等遊戲。

為輸入流的每一行執行一次主循環,在輸入的每一行上計算sed腳本。sed腳本的每一行都是模式-動作對,指示着要匹配的模式和要執行的操作,可以將其重新組合為條件語句。因為主循環、工作變量(模式空間和保持空間)、輸入和輸出流以及默認操作(複製行到模式空間、打印模式空間)是隱式的,所以可以編寫簡潔的單行程序。例如,以下sed程序:

10q

將打印輸入的前10行,然後停止。

用法

替換命令

下面的示例顯示了sed用於替換的典型(也是最常見的)用法。這種用法確實是sed的最初動機:[4]

sed 's/regexp/replacement/g' inputFileName > outputFileName

在某些版本的sed中,表達式的前面必須加上-e,以表示後面跟着一個表達式。s表示替換,而g表示全局,這意味着行中的所有匹配項都將被替換。要搜索的正則表達式(即pattern)放在第一個分隔符號(此處為斜槓)之後,而要替換成的字符串跟在第二個分隔符號後面。斜槓(/)是傳統的符號,起源於ed中的「搜索」字符,但其實在pattern和替換文本中都未出現的任何其他符號都可以用作分隔符號,使其可讀性更強;這有助於避免「傾斜牙籤綜合徵」。

替換命令源自ed中的搜索-替換,實現了簡單的解析和模板化 。regexp提供模式匹配和通過子表達式保存文本的功能,而replacement可以是純文本,也可以是包含「完全匹配」&,或第n 個子表達式(從\1\9)這種特殊轉義序列的格式字符串。例如, sed -r "s/(cat|dog)s?/\1s/g"用「cat」或「dog"替換所有出現的「cats」或「dogs」,而不複製現有的「s」:在正則表達式中,(cat|dog)是第一個(也是唯一)保存的子表達式,格式字符串中的\1將其替換到輸出里。

其他sed命令

除了替換之外,使用大約25個sed命令可以進行其他形式的簡單處理。例如,下面使用d 命令刪除空行或只包含空格的行:

sed '/^ *$/d' inputFileName

本例使用了下列正則表達式元字符(sed支持所有正則表達式):

  • 脫字符( ^ )匹配行首。
  • 美元符號( $ )匹配行尾。
  • 星號* )匹配前一個字符零次或多次出現。

可以有很複雜的sed結構,讓sed用作一種簡單但高度專業化的編程語言。例如,可以通過使用標籤(冒號後跟字符串)和分支指令b來管理控制流程。指令b後跟有效的標籤名稱,將把處理流程移動到該標籤後面的塊。

sed用作過濾器

在Unix下,sed通常用作管道中的過濾器:

generateData | sed 's/x/y/g'

也就是說,諸如「generateData」之類的程序生成數據,然後用sed把x替換成y。例如:

$ echo xyz xyz | sed 's/x/y/g'
yyz yyz

[註 1]

基於文件的sed腳本

將幾個sed命令(每行一個命令)放入腳本文件(例如subst.sed)中然後使用-f選項從文件中運行命令(例如s/x/y/g)通常很有用:

sed -f subst.sed inputFileName > outputFileName

可以在腳本文件中放置任意數量的命令,使用腳本文件也可以避免shell轉義或替換的問題。

這樣的腳本文件可以直接從命令行執行,方法是在其前面加上一個包含sed命令的"shebang行",並為該文件分配可執行權限。例如,可以使用以下內容創建文件subst.sed

#!/bin/sed -f
s/x/y/g

然後,當前用戶可以使用chmod命令使文件可執行:

chmod u+x subst.sed

然後可以直接從命令行執行該文件:

subst.sed inputFileName > outputFileName

就地編輯

GNU sed中引入的-i選項允許就地編輯文件(實際上,在後台創建了一個臨時輸出文件,然後將原始文件替換為臨時文件)。例如:

sed -i 's/abc/def/' fileName

示例

Hello, world! 例子

# convert input text stream to "Hello, world!"
s/.*/Hello, world!/
q

這個「Hello, world!」腳本位於文件(如script.txt)中,並使用sed -f script.txt inputFileName調用,其中「inputFileName」是輸入文本文件。腳本將「inputFileName」第1行更改為「Hello, world!」然後退出,在sed退出之前打印結果。第1行後的任何輸入行都不會被讀取,也不會被打印。唯一的輸出是「Hello, world!」。

這個例子強調了sed的許多關鍵特性:

  • sed是獨一無二的。沒有其他「Hello, world!」例子與之相似。
  • 典型的sed程序相當簡短。
  • sed腳本可以有注釋(以#符號開頭的行)。
  • s(替換)命令是最重要的sed命令。
  • sed允許使用q(退出)等命令進行簡單編程。
  • sed使用正則表達式,例如.* (任何字符的零個或多個)。

其他簡單的例子

下面是各種sed腳本;可以把它們作為參數傳遞給sed,或者放入一個單獨的文件並通過-f執行或通過使腳本本身可執行來執行。

要把文件中某個單詞(例如IRC密碼)替換為「REDACTED」,並保存結果:

sed -i s/yourpassword/REDACTED/ ./status.freenode.log

要刪除包含「yourword」一詞的所有行( 地址 為「/yourword/」):

/yourword/ d

要刪除所有「yourword」這個詞:

s/yourword//g

要同時從文件中刪除兩個單詞:

s/firstword//g
s/secondword//g

為了在一行表示前面的示例,比如在命令行輸入時,可以通過分號連接兩個命令:

sed "s/firstword//g; s/secondword//g" inputFileName

多行處理示例

在下一個示例中,sed(通常僅在一行上工作)會在某一行的後一行以一個空格打頭的情況下刪除換行符。 請考慮以下文本:

This is my dog,
 whose name is Frank.
This is my fish,
whose name is George.
This is my goat,
 whose name is Adam.

下面的sed腳本會將上面的文本轉換為以下文本。請注意,該腳本僅影響以空格開頭的輸入行:

This is my dog, whose name is Frank.
This is my fish,
whose name is George.
This is my goat, whose name is Adam.

使用的腳本是:

N
s/\n / /
P
D

這段腳本應按如下理解:

  • N)將下一行添加到模式空間;
  • s/\n / /)查找一個換行符後跟一個空格,替換為一個空格;
  • P)打印模式空間的頂行;
  • D)從模式空間中刪除頂行並再次運行腳本。

這可以通過分號在一行中表示出來:

sed 'N; s/\n / /; P; D' inputFileName

限制和替代方案

雖然sed具有簡單性和局限性,但對於大量用途而言,它的功能已經足夠強大。對於更複雜的處理,可以使用更強大的語言,如AWKPerl或者PowerShell。雖然使用保持緩衝區理論上可以進行任意複雜的轉換,但如果轉換行的方式比正則表達式提取和模板替換更複雜,則使用一般會使用上面提到的更強大的語言。

相反,對於更簡單的操作,grep (打印匹配模式的行),head(打印文件的第一部分),tail(打印文件的最後部分)和tr(翻譯或刪除字符)等專門的Unix實用程序通常更可取。對於設計用於執行的特定任務,此類專用實用程序通常比較一般的解決方案(如sed)更簡單、清晰和快速。

ed/sed命令和語法繼續用於派生程序,例如文本編輯器vivim。sam/ssam與ed/sed類似,其中sam是Plan 9編輯器,ssam是它的流接口,其功能類似於sed。


注釋

  1. ^ 在命令行使用中,表達式周圍的引號不是必需的,只有在shell不會將表達式解釋為單個字(標記)時才需要。由於腳本s/x/y/g沒有歧義,所以generateData | sed s/x/y/g工作正常。然而,為了清楚起見,通常是要寫引號的,特別是對於有空格的時候(例如,'s/x x/y y/')。大多數情況下,使用單引號是為了避免shell將$解釋為shell變量。使用雙引號,如"s/$1/$2/g",是為了讓shell替換命令行參數或其他shell變量。

參考文獻

  1. ^ The sed FAQ, Section 2.1. [2013-05-21]. (原始內容存檔於2018-06-27). 
  2. ^ The sed FAQ, Section 2.2. [2013-05-21]. (原始內容存檔於2018-06-27). 
  3. ^ 3.0 3.1 McIlroy, M. D. A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (技術報告). CSTR. Bell Labs. 1987 [2018-11-10]. 139. (原始內容存檔 (PDF)於2019-11-30). 
  4. ^ 4.0 4.1 4.2 4.3 On the Early History and Impact of Unix. [2018-11-10]. (原始內容存檔於2017-09-07). A while later a demand arose for another special-purpose program, gres, for substitution: g/re/s. Lee McMahon undertook to write it, and soon foresaw that there would be no end to the family: g/re/d, g/re/a, etc. As his concept developed it became sed… 
  5. ^ Implementation of a Turing Machine as Sed Script. [2018-11-10]. (原始內容存檔於2018-02-20). 
  6. ^ Turing.sed. [2018-11-10]. (原始內容存檔於2018-01-16). 
  7. ^ The $SED Home - gamez. [2009-04-20]. (原始內容存檔於2006-02-08). 
  8. ^ bolknote/SedChess. GitHub. [2018-11-10]. (原始內容存檔於2018-12-02). 
  9. ^ Sedtris, a Tetris game written for sed. [2018-11-10]. (原始內容存檔於2018-12-02). 

擴展閱讀

外部連結

教程

示例

其他鏈接

參見