SED

SED 簡介

When to use SED Stream Editor

SED 特點

SED Characteristics

Operation Model

執行順序 (Execution Sequence)

Drawback

呼叫 Sed (Invoke Sed)

Options

謹慎使用 '-n' 選項

Sed 編輯指令格式

根據位址指定篩選區塊

根據內容指定篩選區塊 (Context Addressing)

Ex 及 Sed 在篩選排除條件表達之異同

對整行的編輯指令

字串代換指令

字串代換指令

Sed 範例:英文電話號碼轉換

輸入輸出指令

多輸入行指令

Hold and Get 指令

流程控制指令

其他指令

Semicolon ';'

Sed 指令索引

Index of sed commands

Squeezing blank lines (like cat -s)

Centering lines

Delete comments from C code

Increment a number

Search make targets

Rename to lower case

chars of lines

lines of files

Transform text into a C 'printf'able string

Prefix non blank lines with their numbers (cat -b)

Prefix lines by their number (cat -n)

Count chars of input (wc -c)

Count lines of input (wc -l)

Count words of input (wc -w)

Print the filename component of a path (basename)

Print directory component of a path (dirname)

Print the first few (=10) lines of input

Print last few (=10) lines of input

The tee(1) command in sed

Print uniq lines of input (uniq)

duplicated lines of input (uniq -d)

Print only and only duplicated lines (uniq -u)

References


Untitled Document
SED 簡介
SED 是一種非互動式的編輯器
   
在作者的個人經驗中,sed 是 Shell Programming 中最常用到的 Unix 附屬工具軟體。 sed 是一種非互動式的編輯器,常常用在 shell script 中的一個小步驟, 使用者無法親眼看到編輯指令的結果, 完全顛覆了一般人對編輯器的認知。事實上,如果沒有sed 這樣的工具, Unix的威力會打一個大大的折扣。 而 sed 的編輯指令與 ed/ex 差不多, 可以視為 ed/ex 的另一版本,專門設計來配合Shell Programming的需求。
除了搭配Shell Programming之外,非互動式的編輯器還有幾個不得不用的情景
 
可以編輯超級巨大的檔案
   
其一是可以編輯超級巨大的檔案。 一般互動式編輯器所能編輯的檔案大小有其上限, 無法編輯大小超過上限的檔案,而且當編輯的檔案越大時,編輯器 就跑得越慢,因為編輯器要不斷的從磁碟機讀取檔案的片段 (亦即太多page fault)。 反之,sed 只需從頭到尾讀取檔案一次即可,每次只需讀進一個 page到主記憶體,檔案可以大到跟作業系統的檔案大小之上限。 換言之,只要是合規的檔案,就能編輯, 而且編輯的速度不受檔案大小之影響。
 
Offline 編輯可降低錯誤
   
第二種情況是,當編輯的指令太複雜, 操作互動式編輯器來編輯檔案時,容易出錯,不如 以offline 方式撰寫 sed 的編輯指令,可以減少錯誤。
 
可重複使用於大批檔案的編輯
   
第三種情況是, 同時要以相同或類似方式編輯一批檔案。例如,台中縣與台中市合併為台中市時, 很多台中縣的文件要修改機關全銜,這時 sed 或ex 等非互動式的編輯器就非常好用了, 使用者只要製作一個編輯指令檔,就可以用來修改一大批檔案,節省無數的工時。
與互動式編輯器相比的主要缺點
   
沒有相對位址
   
無法立即驗證命令是否已如預期執行
Sun Feb 15 10:58:35 CST 2026 Untitled Document
When to use SED Stream Editor
   
To edit files too large for comfortable interactive editing
   
To edit any size file when the sequence of editing commands is too complicated to be comfortably typed in interactive mode
   
To perform multiple 'globle' editing functions efficiently in one pass through the input
Sun Feb 15 10:58:35 CST 2026 Untitled Document
SED 特點
   
既然 sed 編輯指令跟ed/ex 差不多, 所以只要熟習了任何一種就能很快上手其他的。 根據作者多年的經驗,超過九成的機會會用到字串代換這個編輯指令, 所以只要學習幾個基本的編輯指令就可以開始運用在Shell Programming 中了,並不難學習。 下列的例子,是將一批檔案之副檔名從 txt 改為 csv。
範例
for i in *.txt
do
   mv $i `echo $i | sed -e 's/\.txt$//'`.csv
done
Sun Feb 15 10:58:35 CST 2026 Untitled Document
SED Characteristics
 
Most editing commands are the same as ed/ex
 
Good for in-pipe editing
accept target object from STDIN
does not generate temporary files
good for shell script
for i in *.txt
do
   mv $i `echo $i | sed -e 's/\.foo$//'`.csv
done
Sun Feb 15 10:58:36 CST 2026 Untitled Document
Operation Model

sed Command    Man Page

 
空間
樣式空間 (Pattern Space) 臨時緩衝區,用來放置將被編輯的內容
暫存空間 (Hold Space) 用來放置供後續使用的內容
 
執行順序
   
1. script 會依序連接起來,形成一個大 script,
該 script 會被編譯成一個 sed 程式。
2. 從輸入檔案中依序逐行讀入放置於樣式空間, 並根據使用者給定的編輯指令對樣式空間的內容執行編輯動作,
必要時,可存取暫存空間的內容。
3. 將結果輸出於 STDOUT (或傳送到特定的檔案)。
Sun Feb 15 10:58:36 CST 2026 Untitled Document
執行順序 (Execution Sequence)

Scripts are concatenated as they appear, forming a big script.
That script is compiled into a sed program.
That program is then applied to each line of given files (the script itself can change this behavior).
The results are always written to stdout, although same commands can send stuff to specific files
Input files are seen as one to sed, i.e. `sed -n $= *' gives the number of lines of ALL *, something like `cat * | wc -l'
Sun Feb 15 10:58:36 CST 2026 Untitled Document
Drawback
 
Compared with interactive editor:
   
No relative addressing
   
lack of immediate verification that a command has done what was intended
Sun Feb 15 10:58:36 CST 2026 Untitled Document
呼叫 Sed (Invoke Sed)
呼叫 Sed 的方式
sed "10,20p" inputfile
sed -f sed_script inputfile
cat inputfile | sed "10,20p"
cat inputfile | sed -e "10,20p"
cat inputfile | sed -f sed_script
 
註解
inputfile 是待編輯的檔案

sed_script 存放編輯指令
Sun Feb 15 10:58:36 CST 2026 Untitled Document
Options
 -n   
取消預設複製所有讀入行,而只有 p 指令或 s 指令才會輸出。 (預設情況下,sed 會將每一行複製輸出到 STDOUT; 此選項可阻止此行為。也就是說,除非有命令明確指示 Sed 執行輸出(例如 p),否則不會輸出任何內容。)

not to copy all lines, but only those specified by p functions or p flags after s functions


by default, sed writes each line to stdout when it reaches the end of the script (being whatever on the line); this option prevents that. i.e. no output unless there is a command to order SED specifically to do it (like p)
 -e 
將下一個參數作為編輯指令。

take next argument as an editing command

 -f 
將下一個參數作為檔案名稱;該檔案應包含編輯指令,每行一條。

take the next argument as a file name; the file should contain editing commands, one to a line

Sun Feb 15 10:58:37 CST 2026 Untitled Document
謹慎使用 '-n' 選項
   
如果沒有 '-n' 選項,sed 預設會列印每一行。有了該選項,sed 將只列印 p 指令指定的行。下面範例使用下面的 infile
#infile
#==========
AAAA
BBBB
CCCC
DDDD
範例
 
Sed Script   結果   意義
sed "3p" infile
AAAA
BBBB
CCCC
CCCC
DDDD
印出全部,重複第三行
sed -n "3p" infile
CCCC
印出第三行
sed "3q" infile
AAAA
BBBB
CCCC
印出前三行
head -3 infile
Sun Feb 15 10:58:37 CST 2026 Untitled Document
Sed 編輯指令格式
Sed 編輯指令格式
 
[篩選或排除條件][編輯指令][引數(argument)]
1. 篩選或排除條件可以用位址(行號)或內容比對來定義
2. 在篩選條件之後加上'!'即成為排除條件
3. 若無篩選條件,等於全選
4. 引數可有可無
5. 沒有游標
 
我們定義幾個名詞作為後續說明之用:
名詞 意義
篩選區塊 符合篩選條件或不符合排除條件的所有行
篩選行 篩選區塊內的一行
   
Sed 的標準動作是從輸入檔案中將篩選區塊依序逐行讀入放置於樣式空間 並根據使用者給定的編輯指令執行編輯動作。 每次只讀入一行資料並編輯之,也可以利用'N'指令 一次讀入多行資料進行編輯。
   
Multiple line pattern space is allowed by using N command
Sun Feb 15 10:58:37 CST 2026 Untitled Document
根據位址指定篩選區塊
   
Sed 可以根據位址指定篩選區塊。以下是三種指定位址的方式以及範例:
範例
#infile
#==========
AAAA
BBBB
CCCC
DDDD

位址欄數目 作用的標的 範例 Script 結果 說明
0 每一行
sed -n "=" infile 
1
2
3
4
印出行號
1 單一行
sed -n "3=" infile 
3 如果輸入至少有 3 行,則會印出“3”,因為 `=` 指令(列印目前行)只會在第 3 行執行。
sed -n "$=" infile 
4 在最後一行($)印出行號,效果相當於 Shell 指令(wc -l)
2 一個區塊
sed -n "2,3p" infile 
BBBB
CCCC
有 '-n' 選項,sed 只會印出第2,3行,
sed "2,3p" infile 
AAAA
BBBB
BBBB
CCCC
CCCC
DDDD
沒有 '-n' 選項,sed 會印出全部,而第2,3行會重複。
sed -n "2,3!p" infile 
AAAA
DDDD
'!'將篩選條件變成排除條件,效果等同於
sed  "2,3d" infile 
Sun Feb 15 10:58:37 CST 2026 Untitled Document
根據內容指定篩選區塊 (Context Addressing)
 
Sed 可以根據內容指定篩選區塊
   
Sed 使用'//' 作為內容比對之用,可以使用 RegExp
範例
Sed Script   意義
/ABC/d
刪除所有含有ABC字串的行
/ABC/!d
刪除所有未含有ABC字串的行
/^$/d
刪除所有空行,在RegExp 中,'^'及'$'分別代表行首及行尾
/^$/!s/^/%/
將所有非空行之行首加上'%'符號
/.\{73,\}/d
刪除所有長度超過 72 個字元的行
字元'.'代表任意字元,而'{73,}'則代表出現至少73次, '.{73,}'則代表出現至少73個任意字元。

will delete all lines that have more than 72 characters

1,/^$/d
刪除開頭的空白行,即輸出的第一行將不為空。

delete leading blank lines, i.e. the first output line will be non empty

Sun Feb 15 10:58:37 CST 2026 Untitled Document
Ex 及 Sed 在篩選排除條件表達之異同
   
Ex 及 Sed 的格式及指令大致相同,可以減輕很多學習負擔, 但因為操作模式之相異,以致有些不同。編輯指令相同的有d, p, s 等指令, 篩選與排除的方式則大同小異,差異如下:
項目 Ex Sed
指定游標所在行(在互動模式中) . 沒有游標
篩選游標所在行(在互動模式中) /XXX/ 沒有游標
全部篩選 g/XXX/ /XXX/
全部排除 v/XXX/ /XXX/!
Ex 在互動模式中才有游標,在Shell script 中的非互動模式則沒有游標。
Sun Feb 15 10:58:38 CST 2026 Untitled Document
對整行的編輯指令
對整行的編輯指令
  d  
delete lines
刪除篩選區塊
  n  
next line
跳到下一行,樣式空間將會被下一行的內容取代,之後的動作指令將被執行在新的一行。

jumps to next line. i.e. pattern space is replaced with the contents of the next line


execution is prosecuted in the command following the `n' command
  i\
<text>
insert lines
將 <text> 插入在樣式空間之前(每一篩選行之前)

works like the append command, but <text> will be inserted before specified line

  c\
<text>
change lines
將 <text> 取代樣式空間(每一篩選行)

this will delete current pattern space, and replace it with 'text'

  a\
<text>
append lines
將 <text> 插入在樣式空間之後(每一篩選行之後)

add <text> after the specified line


(if address isn't given, then <text> will be added after EACH line of input that executes this)
關於 <text> 的注意事項:
 

<text> 可以有一行以上,每一行之尾端要加上'\'符號:
 
  a\
  1st line\
  2nd\
  .\  last line
  `next command'

假設我們有如下指令:
    sed -e '$a\' -e '<the end>'
結果一行文字 "the end" 會被插入於檔案之後。
 
<text> 的開頭的空白會被省略,如果想保留開頭的空白,必須在前面加上 '\'符號。
 
<text> 的內容會被直接複製,不會被當作編輯指令看待。
 
Note 1 : sed doesn't honor leading spaces, so the leading spaces in <text> will be removed
   
To avoid this behavior, a `\' can be placed before the first space that one wants to see written. That way the space is conveniently escaped and will be treated like a normal char.
 
Note 2: <text> is not processed by the sed program,
   
we insert/change/append raw text directly to output
Sun Feb 15 10:58:38 CST 2026 Untitled Document
字串代換指令
 
字串代換指令: 's'
   
's'是字串代換指令,與 ex 中的代換指令差不多,格式如下:
  s/<pattern>/<replacement>/<flags>

s/要被取代的字串/新的字串/<flag>
Sed 與 ex 在格式上的差別,就是 's'之前沒有指定任何位址,那就會 作用在讀進來的每一行資料。而 ex 中若沒有指定任何位址, 那所下的指令僅作用在游標所在那一行。
   
在 Shell Programming 中使用 Sed, 可以將shell 的變數用於 sed script 中, 很有彈性;例如
  
#將檔案inputfile中所有的Old 改成 New 輸出於 STDOUT 
#=================================================
var1=Old
var2=New
sed "s/$var1/$var2/g" inputfile 
   
注意,在這個 script 中所下達的 sed 編輯指令必須用雙引號括起來,不能使用 單引號,如此,$var1 及 $var2 這兩個 shell 變數才能事先展開形成以下的實際指令:
sed 's/Old/New/g' inputfile
否則, $var1 及 $var2 不會被展開,實際被執行的指令如下:
sed 's/$var1/$var2/g' inputfile
sed 中的字串代換指令所用的分隔符號,可以使用任意字符。
   
習慣上最常用的符號是"/",如果要替換的字串中含有此符號就很不方便,例如下面的例子 要把字串 Dir1/Old 改成字串 Dir2/New:
  sed "s/Dir1\/Old/Dir2\/New/g"
   
如果改用其他符號,如下例,就很方便了:
  sed "s%Dir1/Old%Dir2/New%g"
flag 是選擇性的,而且可以合併使用
  g 將所有出現的符合字串<pattern>換為 <replacement> (預設只替換第一個)。
  p 僅當替換成功時才寫入模式空間。
  w <file> w <file> 的作用與 `p` 標誌相同,但模式空間會寫入 <file>。
  d `d' 是一個數字, 將第 d 個出現的<pattern>(如果有)替換為 <replacement>。
多行的編輯指令
cat file |
    sed "s/Old1/New1/g" |
    sed "s/Old2/New2/g" |
    while read LINE
    do
      some commands
    done
.
cat file |
    sed -e "s/Old1/New1/g" \
        -e "s/Old2/New2/g" |
    while read LINE
    do
      some commands
    done
.
Sun Feb 15 10:58:38 CST 2026 Untitled Document
字串代換指令
 
字串代換 't'
   
  y/<list1>/<list2>/ 
將列表<list2> 中的所有字元代換到列表<list1> 中具有相同位置的字元
remaps all characters presents on <list1> by the character with the same index on <list2>
列表 <list1> 的長度必須與列表 <list2> 的長度相同。
the size of <list1> must be the same as <list2>
所有字元均為字面值,意即單純的字元,沒有特殊意義。
all characters are literals. i.e. no ranges, etc...
分隔符號 `/` 可以替換為任何其他字元。
the separator `/' may be replaced by any other char
Script lowercase
# -----------------------------------------------
# Sed Script: lowercase 將大寫英文字母改成小寫  
# ----------------------------------------------- 
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
Sun Feb 15 10:58:38 CST 2026 Untitled Document
Sed 範例:英文電話號碼轉換
 
將英文字母電話號碼轉換到數字電話號碼
   
如同台灣的個人電腦鍵盤上,除了英文字母外還有標上注音符號以協助 中文打字,美國的電話機按鍵除了數字外還有標上英文字母,很多公司 特意以英文字公布其電話號碼幫助其客戶記住其電話號碼, 例如圖上的 '800-634-LAWS',而其原始電話號碼是,'800-634-5297'。 雖然客戶很容易記住這個電話,但在撥打電話時很不方便,很少人能記住 英文字母的按鍵位置,通常要轉換成數字號碼才方便打電話,本script, 'phone',就是特別為這個用途設計。
用法
  
phone <letter-phone-number>
Script phone_v1
 echo $1 | sed  \ 
 -e 's/[abc]/2/g'   -e 's/[def]/3/g' \ 
 -e 's/[ghi]/4/g'   -e 's/[jkl]/5/g' \ 
 -e 's/[mno]/6/g'   -e 's/[prs]/7/g' \ 
 -e 's/[tuv]/8/g'   -e 's/[wxy]/9/g' 
Script phone_v2
 echo $1 | sed  \ 
  'y/abcdefghijklmnoprstuvwxy/222333444555666777888999/' 
範例
script   結果
phone 634laws
6345297
Sun Feb 15 10:58:38 CST 2026 Untitled Document
輸入輸出指令
Sed Command   意義
  p  
print
  w <filename>  
write on <filename>
  r <filename>  
read the content of <filename>
Sun Feb 15 10:58:39 CST 2026 Untitled Document
多輸入行指令
   
處理含有換行符號(多行)的樣式空間。 主要目的是用在實現跨行樣式匹配。

Deal with pattern spaces containing imbedded newlines.
They are intended principally to provide pattern matches across lines in the input.

Sed 指令   意義
  N  
Next line
下一個輸入行會附加到樣式空間中的目前行;這兩個輸入行之間以一個換行符號 分隔。樣式匹配可以跨越嵌入式換行符號。
The next input line is appended to the current line in the pattern space; the two input lines are separated by an imbedded newline. Pattern matches may extend across the imbedded newline(s).
  D  
Delete first part of the pattern space
刪除目前樣式空間中的第一行,然後續讀下一行重新執行編輯指令。
Delete up to and including the first newline character in the current pattern space.
If the pattern space becomes empty, read another line from the input. In any case, begin the list of editing commands again from its beginning.
  P  
Print first part of the pattern space
印出目前樣式空間中的第一行。
Print up to and including the first newline in the current pattern space.
Sun Feb 15 10:58:39 CST 2026 Untitled Document
Hold and Get 指令
Sed 指令   意義
  h  
hold pattern space
將樣式空間的內容複製到暫存空間,覆蓋暫存空間內原有的內容。。
Copy the contents of the pattern space into a hold area
destroying the previous contents of the hold area.
  H  
Hold pattern space
將樣式空間的內容追加到暫存空間, 接在暫存空間內原有的內容之後,以換行符號分隔。
Append the contents of the pattern space into a hold area.
The former and new contents are separated by a newline.
  g  
get content of hold area
將暫存空間的內容複製到樣式空間, 覆蓋樣式空間原有的內容。
Copy the contents of the hold area into the pattern space
destroying the previous contents of the pattern space.
  G  
Get content of hold area
將暫存空間的內容追加到樣式空間的內容, 新舊內容之間以換行符號分隔。
Append the contents of the hold area to the contents of the pattern space.
The former and new contents are separated by a newline.
  x  
Exchange
交換樣式空間和暫存空間的內容。
Interchanges the contents of the pattern space and the hold area.
Sun Feb 15 10:58:39 CST 2026 Untitled Document
流程控制指令
  !  
Don't;
將篩選條件變成排除條件,(將後續的指令作用在未被選取的範圍-落選者)
例: sed '!s/foo/bar/' 毫無作用,doing nothing
例: sed '/./!d' 刪掉所有空行
  {  
Grouping
跟 C 語言的 grouping 一樣
將數個指令組成一組作用在篩選區塊
後括弧 `}' 必須單獨放在一行
`{...}' 可以有巢狀層次
  :<label>  
Place a label
設一個標籤
trailing space is sensitive
後面的空白是有意義的
  b<label>  
branch to a label
跳到一個標籤處執行
If a label is not given, the default is to jump to the end of the script.
如果沒有指定標籤,則跳至script 之最尾端
  t<label>  
Test substitutions
跟'b'的作用類似,但是在代換的指令執行成功時才跳,否則繼續執行下一行
works like `b', but the jump is only done if a previous substitution has been successfully done (on current pattern space) - the flag that determines if the jump is given on not is: - set on a successful substitution (whatever it was) and reset - reset after `t' been executed - reset after reading a new line
Sun Feb 15 10:58:39 CST 2026 Untitled Document
其他指令
  =  
印出行號到 STDOUT
  q  
印出目前行,並停止
Sun Feb 15 10:58:39 CST 2026 Untitled Document
Semicolon ';'
 
Sed 可以將多行指令合併在一行,中間用';'隔開。

Commands may be separated by semi-colons `;', with some exceptions.

 
例:
Script sed-semicolon
# -----------------------------------------------
# Script sed-semicolon
# ----------------------------------------------- 
sed ':b;/\\\$/{;N;s/\n//;bb;}'
相等於下面的script:
:b
/\\$/{
N
s/\\\n//
bb
}
# -----------------------------------------------
本程式會將輸入檔內尾端是'\'的行去掉'\'並合併次行。

This script would join all lines ended with `\', after deleting the `\' it self
Sun Feb 15 10:58:40 CST 2026 Untitled Document
Sed 指令索引
指令   意義
!
!<cmd> 反篩選(排除),將<cmd>作用在未被排除的行
Don't apply to specified addresses
#
comment
:
:<label> 訂標籤
place a label
=
印出行號
display line number
D
刪掉樣式空間內容的第一行
delete first part of the pattern space
G
將暫存空間的內容接到樣式空間的內容之後
append contents of hold area
H
將樣式空間的內容接到暫存空間的內容之後
append pattern space on buffer
N
將下一行連接在樣式空間內容之後
append next line
P
印出樣式空間內容的第一行
print first part of the pattern space
N
將下一行連接在樣式空間內容之後
append next line
a
將輸入連接在每一篩選行之後
append text
b
b<label> 跳到<label>
branch to label
c
將輸入取代每一篩選行
change lines
d
刪掉每一篩選行
delete lines
g
將暫存空間的內容複製到樣式空間
get contents of hold area
h
將樣式空間的內容複製到暫存空間
hold pattern space
i
將輸入連接在每一篩選行之前
insert lines
l
以可讀的格式列出樣式空間的內容,包括特殊字元的ASCII碼
list lines
n
跳到下一行
next line
p
印出樣式空間的內容
print
q
結束,跳出
quit
r
r <file> 將檔案<file> 讀進樣式空間
read the contents of <file>
t
t<label> 如果代換成功就跳到<label>
test substitutions and branch on successful substitution
w
w <file> 將樣式空間內容存進檔案<file>
write to <file>
x
交換樣式空間和暫存空間的內容
exchange buffer space with pattern space
{
Grouping
s
s/OLD/<New>/[flags]
代換
substitute
y
y/<list1>/<list2>/
將列表<list2> 中的所有字元代換到列表<list1> 中具有相同位置的字元
translates <list1> into <list2>
Sun Feb 15 10:58:40 CST 2026 Untitled Document
Index of sed commands
Operand
數量
Func
tion
  意義
(2)
!
!<cmd> Don't apply to specified addresses
(0)
#
comment
(0)
:
:<label> place a label
(1)
=
display line number
(2)
D
delete first part of the pattern space
(2)
G
append contents of hold area
(2)
H
append pattern space on buffer
(2)
N
append next line
(2)
P
print first part of the pattern space
(1)
a
append text
(2)
b
b<label> branch to label
(2)
c
change lines
(2)
d
delete lines
(2)
g
get contents of hold area
(2)
h
hold pattern space
(1)
i
insert lines
(2)
l
list lines
(2)
n
next line
(2)
p
print
(1)
q
quit
(1)
r
r <file> read the contents of <file>
(2)
t
t<label> test substitutions and branch on successful substitution
(2)
w
w <file> write to <file>
(2)
x
exchange buffer space with pattern space
(2)
{
group commands
(2)
s
s/OLD/<New>/[flags] substitute
(2)
y
y/<list1>/<list2>/ translates <list1> into <list2>
Sun Feb 15 10:58:40 CST 2026 Untitled Document
Script ID Script
sed-eg-1
#replace text
#將所有的 Old 代換成 New
  sed "s/Old/New/g"
sed-eg-2
#remove "XXX"
#將所有的 "XXX" 刪除
  sed "s/XXX//g"
sed-eg-3
#remove "XXX" from front
#將每一行開頭的 "XXX" 刪除
  sed "s/^XXX//"

#'^' 是 RegExp 的行首
sed-eg-4
#remove "XXX" at the end
#將每一行結尾的 "XXX" 刪除
  sed "s/XXX\$//" 
  sed 's/XXX$//'  

#'$' 是 RegExp 的行尾
#請注意單引號與雙引號之使用差異
sed-eg-5
#insert "XXX" in front
#在每一行前面插入 "XXX"
  sed "s/^/XXX/"
sed-eg-6
#append "XXX" to the end
#在每一行後面接上 "XXX"
  sed "s/\$/XXX/g" 
  sed 's/$/XXX/g'
sed-eg-7
#truncate text from "XXX" to the end
#將每一行中的 XXX 字串及之後所有文字全部刪除
  sed "s/XXX.*//" 

#'.' 是 RegExp 的任意字元
#'*' 是 RegExp 的重複任意多次
sed-eg-8
#change tabs to spaces
#將每一個"跳格"取代成為"空格"
  sed "s/<tab>/ /g"
sed-eg-9
#change whitespaces to a single space
#將多個連續的"跳格"或"空格"取代成為一個"空格"
  sed "s/[[:blank:]][[:blank:]]*/ /g"
  sed "s/[[:space:]][[:space:]]*/ /g" 
  sed "s/\s\s*/ /g" 

#[[:blank:]] 是 RegExp 的空格及跳格 (水平定位符、tab)
#[[:space:]] 是 RegExp 的空格、跳格、\t 及 \n等字元
#'\s' 相當於 [[:space:]]
sed-eg-10
#delete leading whitespaces
#刪除每一行最前端的多個連續"跳格"或"空格"
  sed "s/^\s\s*//g"
sed-eg-11
#delete trailing whitespaces
#刪除每一行最末端的多個連續"跳格"或"空格"
  sed 's/\s\s*$//'
sed-eg-12
#delete the lines that contain "XXX"
#將含XXX 字串的行整行全部刪除
  sed "/XXX/d" 
sed-eg-13
#delete empty lines
#刪除空行
  sed '/^$/d'
sed-eg-14
#delete empty lines
#刪除空行,行內若只含空格,視為空行
  sed '/^\s*$/d' 
  sed '/^[[:blank:]]*$/d' 
  sed '/^[[:space:]]*$/d' 
sed-eg-15
#delete first line
#刪除第一行
  sed '1d'
sed-eg-16
#delete first seven lines
#刪除前七行
  sed '1,7d'
sed-eg-17
#delete last line
#刪除最後一行
  sed '$d'
sed-eg-18
#print first line
#印出第一行
  sed -n '1p' 
  sed '2,$d' 
  sed '1q'
sed-eg-19
#print last line
#印出最後一行
  sed -n '$p'
sed-eg-20
#delete comments
#刪除最前端是"#"的行
  sed '/^#/d' 
  sed 's/#.*//'
sed-eg-21
#delete text between lines that contain specific keywords
#從含有字串"Keyword1"的行到含有字串"Keyword2"的行之間全部刪除
  sed '/Keyword1/,/Keyword2/d'
sed-eg-22
#delete text between lines that contain specific keywords
#從只含有字串"Keyword1"的行到只含有字串"Keyword2"的行之間全部刪除
  sed '/^Keyword1$/,/^Keyword2$/d'
sed-eg-23
#extract text between keywords
#從只含有字串"Keyword1"的行到只含有字串"Keyword2"的行之間全部印出
  sed '/^Keyword1$/,/^Keyword2$/!d'
sed-eg-24
#print odd lines
#印出奇數行
   sed -n 'p;n'
sed-eg-25
#print even lines
#印出偶數行
   sed -n 'n;p'
sed-eg-26
#convert < > into HTML code
  cat $* | sed -e 's/</\&lt;/g' -e 's/>/\&gt;/g' 
sed-eg-27
#to print out only the main() function in a C source file
   sed -n -e '/main\s*(/,/^}/p' src.c 
   sed -n -e '/main[[:space:]]*(/,/^}/p' src.c 

#/main\s*(/: 是起始點。 sed 會比對包含 main
#關鍵字、後面接著零或多個空白,最後接左括號 ( 的行。
#,: 逗號定義範圍的開始與結束。
#/^}/: 這是結束點。 sed 會比對行首出現的右大括號 }。
Sun Feb 15 10:58:40 CST 2026 Untitled Document
Squeezing blank lines (like cat -s)
 
Leaves a blank line at the beginning and end, if there are there some already.
 #
# on empty lines, join with next 
# --------------------------------------------------------- 
:x
/^\n*$/{
N
bx
}
   # now, squeeze all '\n', this can be also done by: s/^\(\n\)*/\1/ 
s/\n*/\
/
   #leaves only at end 

#!/usr/bin/sed -f #delete all leading empty lines 1,/^./{ /./!d }
# find an empty line, keep it, and remove all following empty lines
:x /./!{ N s/^\n$// tx }
#Squeeze all, and remove all leading and trailing blank lines. This is also the fastest.
#!/usr/bin/sed -nf # delete all blanks /./!d # get here: so there is a non empty :x # print it p # get next n # got chars? print it again, etc... /./bx # no, don't have chars: another empty line :z # get next n # also empty? then ignore it, and get next... this will remove ALL empty # lines, if we get to end, sed script will finish on n(ext) command # so no trailing empty lines are written /./!bz # all empty lines were deleted/ignored, but we have a non empty, as # what we want to do is to squeeze, insert a blank line artificially i\ bx
Sun Feb 15 10:58:41 CST 2026 Untitled Document
Centering lines
   #!/usr/bin/sed -f 
   # center all lines of a file, on a 80 columns width 
   # 
   # to change that width, the number in \{\} must be replaced, and the number 
   # of added spaces also must be changed 
   # 
   # del leading and trailing spaces 
y/      / /
s/^ *//
s/ *$//
   # add 80 spaces to end of line 
s/$/          /
s/ *$/&&&&&&&&/
   # keep 1st 80 chars 
s/^\(.\{80\}\).*$/\1/
   # split trailing spaces, into two halves, 1st for beg, 2nd to end of line 
s/\( *\)$/#\1%\1/
s/^\(.*\)#\(.*\)%\(.*\)$/\2\1\3/
Sun Feb 15 10:58:41 CST 2026 Untitled Document
Delete comments from C code
   #!/usr/bin/sed -f 
   # if no /* get next 
/\/\*/!b
   # here we've got an /*, append lines until get the corresponding 
   # */ 
:x
/\*\//!{
N
bx
}
   # delete /*...*/ 
s/\/\*.*\*\///
Sun Feb 15 10:58:41 CST 2026 Untitled Document
Increment a number
   #!/usr/bin/sed -f 
   # algorithm by : 
   # Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de> 
   # incrementing one number, is just add 1 to first digit, i.e. replacing 
   # it by the following digit 
   # 
   # there is one exception, when carry does happen, on that case, all 
   # following digits must be added with one 
   # 
   # now this solution by `Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>' 
   # is very clever and smart 
   # 
   # the only way to happen carry, is when the first digit is a 9 
   # all others cases are just fine 
   # 
   # for a number beginning with any digit except 9, just replace it (the digit) 
   # by the next digit, for each number beginning with a 9, just "remove" it and 
   # proceed as above for all others, i.e. all leadings 9s are "removes" until 
   # a non-9 is found, if any 9 did not remain, a 0 is insert 
   # replace all leading 9s by _ (any other char except digits, could be used) 
   # 
:d
s/9\(_*\)$/_\1/
td
   # if there aren't any digits left, add a MostSign Digit 0 
   # 
s/^\(_*\)$/0\1/
   # incr last digit only - there is no need for more 
   # 
s/8\(_*\)$/9\1/
s/7\(_*\)$/8\1/
s/6\(_*\)$/7\1/
s/5\(_*\)$/6\1/
s/4\(_*\)$/5\1/
s/3\(_*\)$/4\1/
s/2\(_*\)$/3\1/
s/1\(_*\)$/2\1/
s/0\(_*\)$/1\1/
   # replace all _ to 0s 
   # 
s/_/0/g
Sun Feb 15 10:58:41 CST 2026 Untitled Document
Search make targets
   #!/usr/bin/sed -nf 
   # make-targets 
   # 
   # tries to catch all targets on a Makefile 
   # 
   # the purpose of this is to be used on the complete [make] feature 
   # of tcsh... so it should be simple and fast 
   # 
   # this is not a shell script, exactly for that reason... hopefully 
   # the kernel will interpret this executable as a sed script and 
   # feed it directly to it 
   # 
   # the name of the makefile, unfortunelly, must be hard coded on the 
   # complete code, and it is "Makefile" 
   # take care of \ ended lines 
:n
/\\$/{
        N
        s/\\\n//
        bn
}
y/      / /
   # delete all comments 
/^ *#/d
s/[^\\]#.*$//
   # register variables, the only ones in here are the ones of form 
   # 
   #       VAR = one_word_def 
   # 
   # in that way, most vars will be skipped, and things like 
   # 
   #       SED_TARGET = sed 
   # 
   # will still work 
   # 
/\([A-Za-z_0-9-]\+\) *= *\([A-Za-z_0-9./-]\+\) *$/{
        s/ //g
        s/$/ /
        H
        b
}
   # now, perform the substitution 
/\$[({][A-Za-z_0-9-]\+[)}]/{
        s/$/##/
        G
        s/\(\$[{(]\)\([A-Za-z_0-9-]\+\)\([)}]\)\(.*\)##.*\2=\([A-Za-z_0-9./-]\+\).*/\5\4/g
}
   # finally, print the targets 
tt
:t
s/^\([A-Za-z_0-9./-]\+\)\(\( \+[A-Za-z_0-9./-]\+\)*\) *:\([^=].*\)\?$/\1\2/
tx
d
   # now, this a final selection of targets to be print 
   # kind of 'prog | grep -v ...' 
   # don't print *.[hco] targets cause in most cases that makes very long output 
:x
/\.[och]$/!p
Sun Feb 15 10:58:42 CST 2026 Untitled Document
Rename to lower case
   #!/bin/sh - 
   # rename files to lower/upper case... 
   # 
   # usage: 
   #       move-to-lower * 
   #       move-to-upper * 
   # or 
   #       move-to-lower -r . 
   #       move-to-upper -r . 
   # 
help()
{
        cat << eof
Usage: $0 [-n] [-r] [-h] files...
-n      do nothing, only see what would be done
-r      recursive (use find)
-h      this message
files   files to remap to lower case
例
       $0 -n *              (see if everything is ok, then...)
       $0 *
       $0 -r
eof } apply_cmd='sh' finder='echo $* | tr " " "\n"' files_only= while : do case "$1" in -n) apply_cmd='cat' ;; -r) finder='find $* -type f';; -h) help ; exit 1 ;; *) break ;; esac shift done [ "$1" ] || { echo Usage: $0 [-n] [-r] files... exit 1 } LOWER='abcdefghijklmnopqrstuvwxyz' UPPER='ABCDEFGHIJKLMNOPQRSTUVWXYZ' case `basename $0` in *to-lower*) FROM=$UPPER; TO=$LOWER ;; *to-upper*) TO=$UPPER; FROM=$LOWER ;; *lower*) FROM=$UPPER; TO=$LOWER ;; *upper*) TO=$UPPER; FROM=$LOWER ;; *) FROM=$UPPER; TO=$LOWER ;; esac eval $finder | sed -n ' # remove all trailing /s s/\/*$// # add ./ if there are no path, only filename /\//!s/^/.\// # save path+filename h # remove path s/.*\/// # do conversion only on filename y/'$FROM'/'$TO'/ # swap, now line contains original path+file, hold space contains conv filename x # add converted file name to line, which now contains something like # path/file-name\nconverted-file-name G # check if converted file name is equal to original file name, if it is, do # not print nothing /^.*\/\(.*\)\n\1/b # now, transform path/fromfile\ntofile, into mv path/fromfile path/tofile # and print it s/^\(.*\/\)\(.*\)\n\(.*\)$/mv \1\2 \1\3/p ' | $apply_cmd
Sun Feb 15 10:58:42 CST 2026 Untitled Document
chars of lines
 
reverse all chars of each line, keep line ordering
   #!/usr/bin/sed -f 
   # ignore empty lines, i.e. nothing to reverse 
/./!b
   # escape ! by doubling it, place markers at beginning and end of line 
   # the markers are -!- which can never happen after the escaping of ! 
s/!/!!/g
s/^/-!-/
s/$/-!-/
   # swaps first char after first maker, with first char before last marker 
   # and then advance the markers through the swapped chars 
ta
:a
s/-!-\([^!]\|!!\)\(.*\)\([^!]\|!!\)-!-/\3-!-\2-!-\1/
ta
   # delete markers, and then unescape the !s 
s/-!-//g
s/!!/!/g
Sun Feb 15 10:58:42 CST 2026 Untitled Document
lines of files
   #!/usr/bin/sed -nf 
   # reverse all lines of input, i.e. first line became last, ... 
   # first line is pasted into buffer 
1{h;b;}
   # for all other lines, the buffer (which contains all previous) 
   # is appended to current line, so, the order is being reversed 
   # on the buffer, after that is done, store everything on the buffer 
   # again 
G;h
   # the last line (after have done the above job) get the contents 
   # of buffer, and print it 
${g;p;}
Sun Feb 15 10:58:42 CST 2026 Untitled Document
Transform text into a C 'printf'able string
   #!/usr/bin/sed -f 
   # The purpose of this script is to construct C programs like this 
   # 
       printf("\
   # common text 
   # ... 
   # 
   # 
   # ... 
   # last line of text 
   # 
   # and then pipe trought this filter the portion between printf and the last 
   # line of text, and get a valid C statement 
   # 
   # That's why, " is placed on last line, and not in first, for eg 
   # escape all special chars " and \ inside a string... 
s/["\\]/\\&/g
   # adds a \n\ to the end of each line, except the last, which gets \n" 
s/$/\\n/
$!s/$/\\/
$s/$/"/
Sun Feb 15 10:58:43 CST 2026 Untitled Document
Prefix non blank lines with their numbers (cat -b)
   #!/usr/bin/sed -nf 
   # copy all lines of input, prefixing only non blank lines by its number, 
   # kind of `cat -b' 
   # init counter 
1{
        x
        s/^/0/
        x
}
   # for blanks, don't incr count, but print 
/./!{
        p
        b
}
   # for the rest is the same as a `cat -n' 
x
:d
s/9\(_*\)$/_\1/
td
s/^\(_*\)$/0\1/
s/8\(_*\)$/9\1/
s/7\(_*\)$/8\1/
s/6\(_*\)$/7\1/
s/5\(_*\)$/6\1/
s/4\(_*\)$/5\1/
s/3\(_*\)$/4\1/
s/2\(_*\)$/3\1/
s/1\(_*\)$/2\1/
s/0\(_*\)$/1\1/
s/_/0/g
s/^/      /
s/^.*\(......\)/\1/
G
s/\n/  /p
s/^ *//
s/  .*//
h
Sun Feb 15 10:58:43 CST 2026 Untitled Document
Prefix lines by their number (cat -n)
   #!/usr/bin/sed -nf 
   # copy all lines of input, prefixed by its number, kind 
   # of `cat -n' 
   # switch to buffer 
x
   # init the counting 
1{
        s/^/0/
}
   # increment the count: first line == number 1 
:d
s/9\(_*\)$/_\1/
td
s/^\(_*\)$/0\1/
s/8\(_*\)$/9\1/
s/7\(_*\)$/8\1/
s/6\(_*\)$/7\1/
s/5\(_*\)$/6\1/
s/4\(_*\)$/5\1/
s/3\(_*\)$/4\1/
s/2\(_*\)$/3\1/
s/1\(_*\)$/2\1/
s/0\(_*\)$/1\1/
s/_/0/g
   # format the number like printf's `"%6d"' 
s/^/      /
s/^.*\(......\)/\1/
   # append the line to the number, and write: "<number>  <line>" 
   # note: this is the format of gnu-cat 
G
s/\n/  /p
   # after printing the line, transform the line into the number, and 
   # store it on buffer again 
s/^ *//
s/  .*//
h
Sun Feb 15 10:58:43 CST 2026 Untitled Document
Count chars of input (wc -c)
   #!/usr/bin/sed -nf 
   # count all chars of input, kind of `wc -c' 
   # the buffer hold the count 
x
1{
        s/^/0/
}
   # we have a line, so at least there is one char: the `\n' 
tx
:x
s/9\(_*\)$/_\1/
tx
s/^\(_*\)$/0\1/
s/ \(_*\)$/0\1/
s/8\(_*\)$/9\1/
s/7\(_*\)$/8\1/
s/6\(_*\)$/7\1/
s/5\(_*\)$/6\1/
s/4\(_*\)$/5\1/
s/3\(_*\)$/4\1/
s/2\(_*\)$/3\1/
s/1\(_*\)$/2\1/
s/0\(_*\)$/1\1/
s/_/0/g
   # get back to the line 
x
   # for each char in the line, increment the count 
tc
:c
s/.//
x
tx
   # on last line, all is done, so print the count, and quit 
${p;q;}
   # put current line (which has been swapped with the count) to the buffer 
h
Sun Feb 15 10:58:43 CST 2026 Untitled Document
Count lines of input (wc -l)
   #!/usr/bin/sed -nf 
   # count lines of input, kind of `wc -l' 
$=
Sun Feb 15 10:58:43 CST 2026 Untitled Document
Count words of input (wc -w)
   #!/usr/bin/sed -nf 
   # count all words on input 
   # words are separated by tabs, newlines and spaces 
   # the buffer hold the count 
1{;x;s/^/0/;x;}
s/^[     ]*/\
/
ts
:t
s/^/w/
ts
:s
s/^\(.*\n\)[^   ]\+[    ]*/\1/
tt
s/\n.*$//
   # the above, replaced all words by `w', and delete everything else 
   # except newlines, so, now the job to do, is only of counting chars 
   # 
   # from this on, this is the same os count-chars, by first we must 
   # delete one char (to keep up with the extra newline) 
/./!{;${;g;p;q;};d;}
s/.//
x
   # we have a line, so at least there is one char: the `\n' 
tx
:x
s/9\(_*\)$/_\1/
tx
s/^\(_*\)$/0\1/
s/ \(_*\)$/0\1/
s/8\(_*\)$/9\1/
s/7\(_*\)$/8\1/
s/6\(_*\)$/7\1/
s/5\(_*\)$/6\1/
s/4\(_*\)$/5\1/
s/3\(_*\)$/4\1/
s/2\(_*\)$/3\1/
s/1\(_*\)$/2\1/
s/0\(_*\)$/1\1/
s/_/0/g
   # get back to the line 
x
   # for each char in the line, increment the count 
tc
:c
s/.//
   # put count on line 
x
tx
   # update buffer with count 
h
   # on last line, all is done, so print the count 
$p
Sun Feb 15 10:58:44 CST 2026 Untitled Document
Print the filename component of a path (basename)
   #!/usr/bin/sed -f 
   # usage: fbasename file 
   # or 
   # usage: find path -print | fbasename 
   # 
   # 
   # this is a basename, but read filenames from stdin, each line 
   # contains the path and a possible suffix 
   # 
   # this will produce one output line per input line, with 
   # the filename component of path, with the (possible) suffix 
   # removed 
s/^[    ]*//
s/[     ]*$//
tc
:c
s/[     ][      ]*/\
/
ta
s/\/*$//
s/.*\///
b
:a
h
s/.*\n//
x
s/\n.*//
s/\/*$//
s/.*\///
tb
:b
G
s/^\(.*\)\(.*\)\n\2$/\1/
t
P
d
Sun Feb 15 10:58:44 CST 2026 Untitled Document
Print directory component of a path (dirname)
   #!/usr/bin/sed -f 
   # usage: find path -print | fdirname 
   # 
   # fdirname acts like dirname, but read files from stdin 
   # print the directory component of a path 
   # special case: `/' is given 
/^\/$/c\
/
   # strip trailing `/'s if any 
s/\/*$//
   # strip trailing filename 
s/[^/]*$//
   # if get no chars after these, then we have current dir (things like 
   # `bin/ src/' were given 
/./!c\
  • # delete the trailing `/' # ("/usr/bin/ls" --> "/usr/bin/", this makes "/usr/bin") s/\/$//
  • Sun Feb 15 10:58:44 CST 2026 Untitled Document
    Print the first few (=10) lines of input
       #!/usr/bin/sed -f 
       # display first 10 lines of input 
       # the number of displayed lines can be changed, by changing the number 
       # before the `q' command to `n' where `n' is the number of lines wanted 
    10q
    
    Sun Feb 15 10:58:44 CST 2026 Untitled Document
    Print last few (=10) lines of input
       #!/usr/bin/sed -f 
       # this is a tail command, it displays last 10 lines of input 
       # if there are 10 or more, if less than that, displays all 
       # to change number of displayed lines, the "$b;N" number of 
       # statements after the "1{" must be changed to `n-2', where `n' 
       # is the number of pretended lines, e.g. if want 10 lines, 
       # should have 8 `$b;N' 
       # to do that with vi, just goto the first `$b,N' and do `d/^}/-2 dd 8p' 
    1{
            $b;N
            $b;N
            $b;N
            $b;N
            $b;N
            $b;N
            $b;N
            $b;N
    }
    $b;N
    $!D
    
    Sun Feb 15 10:58:44 CST 2026 Untitled Document
    The tee(1) command in sed
       #!/bin/sh - 
       # emulation of tee using sed, and a sh(1) for cycle 
    cmd=
    for i
    do
            cmd="$cmd -e 'w $i'"
    done
    eval sed $cmd
    
    Sun Feb 15 10:58:45 CST 2026 Untitled Document
    Print uniq lines of input (uniq)
       #!/usr/bin/sed -f 
       # print all uniq lines on a sorted input-- only one copy of a duplicated 
       # line is printed 
       # like `uniq' 
    :b
    $b
    N
    /^\(.*\)\n\1$/{
            s/.*\n//
            bb
    }
    $b
    P
    D
    
    Sun Feb 15 10:58:45 CST 2026 Untitled Document
    duplicated lines of input (uniq -d)
       #!/usr/bin/sed -nf 
       # print all duplicated uniq lines on a sorted input 
       # like `uniq -d' 
    $b
    N
    /^\(.*\)\n\1$/{
            s/.*\n//
            p
            :b
            $b
            N
            /^\(.*\)\n\1$/{
                    s/.*\n//
                    bb
            }
    }
    $b
    D
    
    Sun Feb 15 10:58:45 CST 2026 Untitled Document
    Print only and only duplicated lines (uniq -u)
       #!/usr/bin/sed -f 
       # print all uniq lines on a sorted input-- no copies of duplicated 
       # lines are printed 
       # like `uniq' 
    $b
    N
    /^\(.*\)\n\1$/!{
            P
            D
    }
    :c
    $d
    s/.*\n//
    N
    /^\(.*\)\n\1$/{
            bc
    }
    D
    
    Sun Feb 15 10:58:45 CST 2026 Untitled Document
    References
    Reference Book sed & awk, by Dougherty, Dale and Robbins, Arnold from Oreilly & Associates, ISBN 1-56592-225-5
    GNU sed ftp://ftp.gnu.org/gnu/sed/.
    An excellent source http://sed.sourceforge.net/.
    FAQ http://www.dreamwvr.com/sed-info/sed-faq.html.
    FAQ ftp://rtfm.mit.edu/pub/faqs/editor-faq/sed.
    Sun Feb 15 10:58:45 CST 2026