?? sed.txt
字號:
sed - 非交互式文本編輯器
sed 是在 UNIX操作系統上運行的一個非交互式上下文編輯器。sed 被設計在下列三種情況下發揮作用:
* 1) 編輯那些對舒適的交互式編輯而言太大的文件。
* 2) 在編輯命令太復雜而難于在交互模式下鍵入的時候編輯任何大小的文件。
* 3) 要在對輸入的一趟掃描中有效的進行多個‘全局’編輯函數。
目錄
* 介紹
* 1. 整體操作
o 1.1. 命令行標志
o 1.2. 編輯命令的應用次序
o 1.3. 模式空間
o 1.4. 示例
+ 例子
* 2. 地址: 選擇要編輯的行
o 2.1. 行號地址
o 2.2. 上下文地址
o 2.3. 地址的數目
o 例子
* 3. 函數
o 3.1. 面向整行的函數
+ 例子
o 3.2. 替換函數
+ 例子
o 3.3. 輸入輸出函數
+ 例子
o 3.4. 多輸入行函數
o 3.5. 保存和取回函數
+ 例子
o 3.6. 控制流函數
o 3.7. 雜類函數
* 引用
介紹
sed 是一個非交互式上下文(context)編輯器,它被設計在下列三種情況下發揮作用:
1) 編輯那些對舒適的交互式編輯而言太大的文件。2) 在編輯命令太復雜而難于在交互模式下鍵入的時候編輯任何大小的文件。3) 要在對輸入的一趟掃描中有效的進行多個‘全局’(global)編輯函數。
因為每次只把輸入的某些行駐留在內存中,并且不使用臨時文件,所以可編輯的文件的有效大小,只受限于輸入和輸出要同時共存于次級存儲的要求。
可以單獨的建立復雜的編輯腳本并作為給 sed 的命令文件。對于復雜的編輯,這節省了可觀的鍵入和隨之而來的錯誤。從命令文件運行 sed 高效于作者所知道的任何交互式編輯器,甚至包括能用預先寫好的腳本驅動的編輯器。
相較于交互式編輯器而言,根本性的損失是缺乏相對地址(由于操作是每次一行的),和缺乏對命令如期運行的立即驗證。
sed 是 UNIX 編輯器 ed 的直系后代。由于在交互式和非交互式操作之間的差異,在 ed 和 sed 之間已經有了可觀的變化;甚至 ed 的慣常用戶都會經常感到驚訝(并可能氣憤),如果他們沒有閱讀本文檔的章節 2 和 3,就草率的使用 sed 的話。在兩個編輯器之間最顯著的家族性共同之處,在于他們所識別的模式(‘正則表達式’)的種類;匹配模式的代碼可以從 ed 的代碼幾乎原封不動的復制過來,在章節 2 中對正則表達式的描述就是從 UNIX Programmer’s Manual[1] 幾乎原封不動的復制過來的。(代碼和描述都是 Dennis M. Ritchie 寫的)。
1. 整體操作
sed 缺省的把標準輸入復制到標準輸出,在把每行寫到輸出之前可能在其上進行一個或多個編輯命令。這種行為可以通過命令行上的標志來更改;參見下面的章節 1.1。
編輯命令的一般格式為:
[地址1,地址2][函數][參數]
一個或兩個地址是可以省略的;地址的格式在章節 2 中給出。可以用任何數目的空白或 tab 把地址和函數分隔開。函數必須出現;在章節 3 中討論可用的所有命令。依據給出的是哪個函數,參數可能是必需的或是可選的;它們在章節 3 中每個單獨的函數之下討論。
忽略在這些行開始處的 tab 字符和空格。
1.1. 命令行標志
在命令行上識別三個標志:
* -n:告訴 sed 不復制所有的行,只復制 p 函數或在 s 函數后 p 標志所指定的行(參見章節 3.3)。
* -e:告訴 sed 把下一個參數接受為編輯命令。
* -f:告訴 sed 把下一個參數接受為文件名;這個文件應當包含一行一個的編輯命令。
1.2. 編輯命令的應用次序
在做任何編輯之前(實際上,甚至在打開任何文件之前),所有編輯命令都被編譯成了在執行階段(在把這些命令實際應用于輸入文件的行的時候)有適當效率的形式。按它們出現的次序編譯這些命令;一般而言這也是在執行時嘗試應用它們的次序。這些命令一次應用一個;給每個命令的輸入都是所有前面命令的輸出。
編譯命令應用的缺省的線性次序可以通過控制流命令 t 和 b 來變更(參見章節 3)。即使在應用次序被這些命令改變的時候,給任何命令的輸入仍是任何此前應用的命令的輸出。
1.3. 模式空間
模式匹配的范圍叫做模式空間。一般而言,模式空間是輸入文本中某一行,但是可以通過使用 N 命令把多于一行讀入模式空間(參見章節 3.6.)。
1.4. 示例
例子分散在正文中。除非特別說明,例子都假定了下列輸入文本:
In Xanadu did Kubla Khan
A stately pleasure dome decree:
Where Alph, the sacred river, ran
Through caverns measureless to man
Down to a sunless sea.
(在任何情況下 sed 命令的輸出都不能被當作是對 Coleridge 作品的改進。)
例子:
命令
2q
會在復制了輸入的前兩行之后退出。輸出將是:
In Xanadu did Kubla Khan
A stately pleasure dome decree:
2. 地址: 選擇要編輯的行
編輯命令要應用于其上的,輸入文件中的行可以通過地址來選擇。地址可以是行號或者是上下文地址。
通過用花括號(‘{ }’)組合(group)命令,可以用一個地址(或地址對)來控制一組命令的應用(參見章節 3.6.)。
2.1. 行號地址
行號是十進制整數。在從輸入讀入每一行的時候,增加一個行號計數器;行號地址匹配(選擇)導致這個內部計數器等于地址行號的輸入行。計數器在多個輸入文件上累計運行,在打開一個新文件的時候它不被復零(reset)。
作為特殊情況,字符 $ 匹配輸入文件的最后一行。
2.2. 上下文地址
上下文地址是包圍在斜杠中(‘/’)的模式(‘正則表達式’)。sed 識別的正則表達式被構造如下:
* 1) 普通字符(不是下面討論的某個字符)是一個正則表達式,并且匹配這個字符。
* 2) 在正則表達式開始處的‘^’符號(circumflex)匹配在行開始處的空(null)字符。
* 3) 在正則表達式結束處的美元符號‘$’匹配在行結束處的空字符。
* 4) 字符‘\n’匹配內嵌的換行字符,而不是在模式空間結束處的換行。
* 5) 點‘.’匹配除了模式空間的終止換行之外的任何字符。
* 6) 跟隨著星號‘*’的正則表達式,匹配它所跟叢的正則表達式的任何數目(包括 0)的毗連出現。
* 7) 在方括號‘[ ]’內的字符串,匹配在字符串內的任何字符,而非其他。但是如果這個字符串的第一個字符是‘^’符號,正則表達式匹配除了在這個字符串內的字符和模式空間的終止換行之外的任何字符。
* 8) 正則表達式的串聯(concatenation)是正則表達式,它匹配這個正則表達式的成員所匹配的字符串的串聯。
* 9) 在順序的‘\(’和‘\)’之間的正則表達式,在效果上等同于沒有它修飾的正則表達式,但它有個副作用,將在下面的 s 命令和緊后面的規定 10 中描述。
* 10) 表達式‘\d’意味著與在同一個表達式中先前的‘\(’和‘\)’中包圍的表達式所匹配的那些字符同樣的字符串。這里的 d 是一個單一的數字;指定的字符串是‘\(’的從左至右的第 d 個出現所起始的字符串。例如,表達式‘^\(.*\)\1’匹配開始于同一個字符串的兩次重復出現的行。
* 11) 孤立的空正則表達式(就是‘//’)等價于編譯的最后一個正則表達式。
要使用特殊字符(^ $ . * [ ] \ /)中的某一個字符作為文字(去匹配輸入中它們自身的出現),要對這個特殊字符前導一個反斜杠‘\’。
上下文地址‘匹配’輸入要求地址內的整個模式匹配模式空間的某個部分。
2.3. 地址的數目
在下一章節中的命令可能有 0, 1 或 2 個地址。在每個命令中都給出了允許的地址的最大數目。地址多于最大允許個數的命令被認為是錯誤的。
如果命令沒有地址,它應用于輸入中每個行。
如果命令有一個地址,它應用于匹配這個地址的所有行。
如果命令有兩個地址,它應用于匹配第一個地址的第一行,和直到(并包括)匹配第二個地址的第一個后續行的所有后續行。接著在后續的行上再次嘗試匹配第一個地址,并重復這個處理。
兩個地址用逗號分隔。
例子:
/an/ 匹配我們樣例文本的第 1, 3, 4 行
/an.*an/ 匹配第 1 行
/^an/ 沒有匹配行
/./ 匹配所有行
/\./ 匹配第 5 行
/r*an/ 匹配第 1,3, 4 行(number = zero!)
/\(an\).*\1/ 匹配第 1 行
3. 函數
所有函數都用一個單一字符來命名。在下面的總結中,允許地址的最大數目在成對的圓括號內給出,接著的單一字符是函數名字,可能有的參數包圍在成對的尖括號(< >)內,單一字符名字的英語解釋,并在最后描述每個函數做些什么。在參數外圍的尖括號不是參數的一部分,在實際編輯命令中不應該鍵入。
3.1. 面向整行的函數
(2)d -- delete lines
d 函數從文件中刪除(不寫入輸出)匹配它的地址的所有行。
它還有一個副作用,在這個已刪除的行上將不再嘗試進一步的命令;在執行了 d 之后,馬上就從輸入讀取一個新行,在新行上從頭重新啟動編輯命令列表。
(2)n -- next line
n 函數從輸入讀取下一行,替代當前行。當前行被寫入輸出,如果應該的話。繼續執行編輯命令列表在 n 命令之后的部分。
(1)a\
<文本> -- append lines
a 函數導致在匹配它的地址的行之后把參數<文本>寫入輸出。a 命令是天生多行的;a 必須出現在一行的結束處,而<文本>可以包含任意數目的行。為了保持一行一個命令的構想,內部的換行必須用給換行立即前導上反斜杠字符(‘\ ’)的方式來隱藏。<文本>參數終止于第一個未隱藏的換行(沒有立即前導反斜杠的第一個換行)。
一旦 a 函數成功的執行了,<文本>將被寫入輸出,而不管后來的命令對觸發它的行會做些什么。觸發的行可以被完全刪除掉;而<文本>仍會被寫入輸出。
<文本>不被地址匹配所掃描,不嘗試對它做編輯命令。它不引起行號計數器的任何變化。
(1)i\
<文本> -- insert lines
i 函數表現得等同于 a 函數,除了<文本>在匹配行之前寫入輸出之外。關于 a 函數的所有其他注釋同樣適用于 i 函數。
(2)c\
<文本> -- change lines
c 函數刪除它的地址所選擇的那些行,并把它們替代為在<文本>中的行。象 a 和 i 一樣,c 必須跟隨著被反斜杠隱藏了的換行;并且在<文本>中的內部的換行必須用反斜杠隱藏。
c 命令可以有兩個地址,所以可選擇一定范圍內的行。如果找到,在這個范圍內的所有行都被刪除,只把<文本>的一個復本寫入輸出,而不是對每個刪除的行都寫一個復本。同于 a 和 i,<文本>不被地址匹配所掃描,不嘗試對它做編輯命令。它不引起行號計數器的任何變化。
在一行已經被 c 函數刪除之后,在這個已刪除的行上將不再嘗試進一步的命令。
如果 a 或 r 函數在某一行之后添加了文本,而這一行隨后被 c 函數變更了,則 c 函數所插入的文本將會放置在 a 或 r 函數的文本之前。(r 函數在章節 3.4. 中描述)。
注意: 在這些函數放入輸出的文本內,前導的空白和 tab 都會消失,象 sed 的編輯命令一樣。要把前導的空白和 tab 放入輸出中,需要在想要的第一個空白或 tab 之前前導反斜杠;這個反斜杠不會出現在輸出中。
例子:
編輯命令的列表:
n
a\
XXXX
d
應用于我們的標準輸入,生成:
In Xanadu did Kubhla Khan
XXXX
Where Alph, the sacred river, ran
XXXX
Down to a sunless sea.
在這個特定情況下,下面兩列命令列表會生成同樣的效果:
n n
i\ c\
XXXX XXXX
d
3.2. 替換函數
這是一個非常重要的函數,它改變在一行之內通過上下文查找而選擇出的這一行的某部分。
(2)s<模式><替代><標志> -- substitute
s 函數替代行的(通過<模式>選擇的)某部分為<替代>。它可以讀做:
替換<模式>為<替代>
<模式>參數包含一個模式,它完全等同于地址中的模式(參見章節 2.2)。在<模式>和上下文地址之間的唯一區別是上下文地址必須用斜杠字符(‘/’)來界定;<模式>可以用不是空格或換行的任何其他字符來界定。
缺省的,只替換匹配<模式>的第一個字符串,參見后面的 g 標志。
<替代>參數緊接著<模式>的第二個分界字符之后開始,并且它必須立即跟隨著分界字符的另一個實例。(所以準確的有三個分界字符的實例)。<替代>不是模式,在模式中有特殊意義的字符在<替代>中沒有特殊意義。反而有特殊意義的字符是:
* & 被替代為匹配<模式>的字符串。
* \d (這里的 d 是一個單一的數字)被替代為同<模式>中第 d 個包圍在‘\(’和‘\)’內的部分相匹配的子串。如果在<模式>中出現嵌套的子串,第 d 個通過計數開分界符 (‘\(’)來界定。同在模式中一樣,特殊字符可以通過前導反斜杠(‘\’)來變為文字。
<標志>參數可以包含任何下列標志:
* g -- 把此行中<模式>的所有(不重疊)的實例都替換為<替代>,對<模式>的下一個實例的掃描就開始于插入的 這些字符之后;放置入行中的來自<替代>的字符不會被重新掃描。
* p -- 打印此行,如果做了成功替換的話。p 標志導致把輸入行寫入輸出,當且僅當這個 s 函數實際上做了替換。注意如果有多個 s 函數,每個函數都跟隨著 p 標志,它們都在同一個輸入行上成功的做了替換,會把這一行的多個復本寫到輸出: 每個成功的替換都寫一個復本。
* w <文件名> -- 把此行寫入一個文件,如果做了成功的替換的話。w 標志導致實際上被 s 函數替代了那些行被寫到<文件名>所指名的文件中。如果<文件名>在 sed 運行前就存在,則覆蓋它。否則,就建立它。
必須用一個單一的空格分隔 w 和<文件名>。
同 p 一樣有著寫入一個輸入行的多個略有不同的復本的可能性。
在 w 標志和 w 函數(參見后面章節)之后可以提及的不同的文件名字合起來的最大數目為 10 個。
例子:
把下列命令應用于我們的標準輸入,
s/to/by/w changes
生成,在標準輸出上:
In Xanadu did Kubhla Khan
A stately pleasure dome decree:
Where Alph, the sacred river, ran
Through caverns measureless by man
Down by a sunless sea.
在文件‘changes’中:
Through caverns measureless by man
Down by a sunless sea.
如果不復制選項生效,命令:
s/[.,;?:]/*P&*/gp
生成:
A stately pleasure dome decree*P:*
Where Alph*P,* the sacred river*P,* ran
Down to a sunless sea*P.*
最后為了展示 g 標志的效果,命令:
/X/s/an/AN/p
生成(假定不復制模式):
In XANadu did Kubhla Khan
而命令:
/X/s/an/AN/gp
生成:
In XANadu did Kubhla KhAN
3.3. 輸入輸出函數
(2)p -- print
打印函數把尋址到的行寫到標準輸出文件。在遇到 p 函數的時候就寫入它們,而不管后續的編輯命令對這些行會做些什么。
(2)w <文件名> -- write on <filename>
寫函數把尋址到的行寫到<文件名>指名的文件中。如果這個文件以前就存在,則覆蓋它;否則,就建立它。每行都按遇到寫函數時現存的樣子寫入,而不管后續的編輯命令對這些行會做些什么。必須用精確的一個空格分隔 w 和<文件名>。在 s 函數的 w 標志之后和寫函數中可以提及的不同的文件名字合起來的最大數目為 10 個。
(1)r <文件名> -- read the contents of a file
讀函數讀入<文件名>的內容,并把它們添加到匹配這個地址的行的后面。讀取這個文件并添加它的內容,而不管后續的編輯命令對匹配它的地址的這些行會做些什么。如果 r 和 a 函數在同一行上執行,來自 a 函數和 r 函數的文本按照這些函數執行的次序寫入輸出。必須用精確的一個空格分隔 r 和<文件名>。如果 r 函數提及的文件不能打開,它被當作一個空文件,而不是一個錯誤,所以不給出診斷信息。
注意: 因為對可以同時打開的文件數目是有所限制的,要小心在 w 命令或標志中不要提及多于 10 個(不同的)文件;如果有任何 r 函數出現,這個數目還會再減少一個。(在一個時候只能打開一個讀取文件)。
例子
假定文件‘note1’有如下內容:
Note: Kubla Khan (more properly Kublai Khan; 1216-1294) was the grandson and most eminent successor of Genghiz (Chingiz) Khan, and founder of the Mongol dynasty in China.
則下列命令:
/Kubla/r note1
生成:
In Xanadu did Kubla Khan
Note: Kubla Khan (more properly Kublai Khan; 1216-1294) was the grandson and most eminent successor of Genghiz (Chingiz) Khan, and founder of the Mongol dynasty in China.
A stately pleasure dome decree:
Where Alph, the sacred river, ran
Through caverns measureless to man
Down to a sunless sea.
3.4. 多輸入行函數
有三個用大寫字母拼寫的函數特殊處理包含內嵌換行的模式空間;它們主要意圖提供跨越輸入中的行的模式匹配。
(2)N -- Next line
在模式空間中把下一行添加到當前行之后;兩個輸入行用一個內嵌的換行分隔。模式匹配可以延伸跨越這個內嵌換行。
(2)D -- Delete first part of the pattern space
刪除當前模式空間中直到并包括第一個換行字符的所有字符。如果這個模式空間變成了空的(唯一的換行是終止換行),則從輸入讀取另一行。在任何情況下,都再次從編輯命令列表的起始處開始執行。
(2)P -- Print first part of the pattern space
打印模式空間中的直到并包括第一個換行的所有字符。
P 和 D 函數等價于它們對應的小寫函數,如果在模式空間中沒有內嵌換行的話。
3.5. 保存和取回函數
有四個函數為將來的使用而保存和取回部分輸入。
(2)h -- hold pattern space
h 函數把模式空間的內容復制到保存區域(銷毀保存區域以前的內容)。
(2)H -- Hold pattern space
H 函數把模式空間的內容添加到保存區域的內容之后;以前和新的內容用換行分隔。
(2)g -- get contents of hold area
g 函數把保存區域的內容復制到模式空間(銷毀模式空間以前的內容)。
(2)G -- Get contents of hold area
G 函數把保存區域的內容添加到模式空間的內容之后;以前和新的內容用換行分隔。
(2)x -- exchange
對換命令交換模式空間和保存區域的內容。
例子
命令
1h
1s/ did.*//
1x
G
s/\n/ :/
應用于我們的標準例子,生成:
In Xanadu did Kubla Khan :In Xanadu
A stately pleasure dome decree: :In Xanadu
Where Alph, the sacred river, ran :In Xanadu
Through caverns measureless to man :In Xanadu
Down to a sunless sea. :In Xanadu
3.6. 控制流函數
這些函數不在輸入行上做編輯,但是控制函數到地址部分所選擇的行的應用。
(2)! -- Don’t
非命令導致(寫在同一行上的)下一個命令,應用到所有的且只能是未被地址部分選擇到那些輸入行上。
(2){ -- Grouping
組合命令‘{’導致下一組命令作為一個塊而被應用(或不應用)到組合命令的地址所選擇的輸入行上。在組合控制下的的命令中的第一個命令可以出現在與‘{’相同的一行或下一行上。
組合的命令由自己獨立在一行之上的相匹配的‘}’終止。
組合可以嵌套。
(0):<標號> -- place a label
標號函數在編輯命令列表中標記一個位置,它將來可以被 b 和 t 函數所引用。<標號>可以是八個或更少的字符的任何序列;如果兩個不同的冒號函數有相同的標號,就會生成編譯時間診斷信息,而不做執行嘗試。
(2)b<標號> -- branch to label
分支函數導致應用于當前輸入行上的編輯命令序列,被立即重新啟動到有相同的<標號>的冒號函數的所在位置之后。如果在所有編輯命令都已經被編譯了之后仍沒有找到有相同的標號的冒號函數,就會生成一個編譯時間診斷信息,而不做執行嘗試。
不帶有<標號>的 b 函數被當作到編輯命令列表結束處的分支;對當前輸入行做應做的無論怎樣的處理,并讀入其他輸入行;編輯命令的列表在這個新行上從頭重新啟動。
(2)t<標號> -- test substitutions
t 函數測試在當前輸入行上是否已經做了任何成功的替換;如果有,它分支到<標號>;否則,它什么都不做。指示已經執行了成功的替換的標志通過如下方式復零:
* 1) 讀取一個新輸入行,或
* 2) 執行 a 和 t 函數。
3.7. 雜類函數
(1)= -- equals
= 函數向標準輸出寫入匹配它的地址的行的行號。
(1)q -- quit
q 函數導致把當前行寫到標準輸出(如果應該的話),任何添加的或讀入的文本也被寫出,而且執行會被終止。
引用
[1] Ken Thompson and Dennis M. Ritchie, The UNIX Programmer’s Manual. Bell Laboratories, 1978.
原文地址 http://cm.bell-labs.com/7thEdMan/vol2/sed
發表于: 2006-06-27,修改于: 2006-07-04 20:57,已瀏覽8769次,有評論1條 推薦 投訴
網友: lgfang 時間:2006-06-28 11:20:13 IP地址:192.11.188.★
原文是man-page,無法直接看,我用emacs把它格式化了:
SED -- A Non-interactive Text Editor
Lee E. McMahon
Context search Editing
Sed is a non-interactive context editor that runs on the
operating system. Sed is designed to be especially useful in
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -