sed 命令
sed 簡述
sed [選項] [指令碼] [輸入檔案]
|
在命令列上執行 script (指令),只有一組指令時可不需要本選項。 |
|
支援延伸正規表示法(預設是基本正規表示法)。 |
|
執行 script-file (指令檔), sed 的指令是在指令檔內。 |
|
直接修改檔案內容。 |
|
separate lines by NUL characters,將換行以 NUL 字元取代,取代換行時需本選項。 |
|
不自動列印 (模式空間)。 |
sed 's/pattern/replacement/flags' inputFileName > outputFileName
替代命令 (在指令碼中第一個字母 s
) 將 inputFileName 的內容與提供的樣板 (pattern) 匹配;當匹配成功則將樣板替換為「替換文字 (replacement)」。
/ (斜線) 是傳統的定界字元 (delimiter),但;其實在 pattern 和 replacement 中都未出現的其他字元都可以當作定界字元。pattern 和 replacement 常稱為 正規表示法。
sed 命令中可以用單引號 ('
) 和雙引號 ("
),一般習慣採用單引號,但是如果要使用 shell 變數就需要使用雙引號。
flags 指定為 g
時,表示 全域性更改。
將下列的 is 改成 is a:
echo 'this is book, that is bicycle' | sed -e 's/ is / is a /' (1)
this is a book, that is bicycle
以全域性 (g) 更改:
echo 'this is book, that is bicycle' | sed 's/ is / is a /g'
this is a book, that is a bicycle
1 | 只有一組指令,可不需要 -e 選項。 |
正規表示法
正規表示式 (英語: Regular Expression,簡寫為 regex、regexp 或 RE),又稱正規表示法。正規表示法分為基本正規表示法(Basic Regular Expression,BRE)和延伸正規表示法(Extended Regular Expression,ERE)。
sed 採用 ERE 的選項為 -E
或 -r
。
- 正規表示法的特殊字元
-
. * ^ $ / \ [ ]
上述特殊字元作為文字字元時,需要在特殊字元前加入「跳脫字元 (Escape Character)
\
(反斜線)」 來轉譯它。:sed 的定界字元如果是
/
(斜線),那麼文字字元的「斜線」要轉譯成\/
,如果不是則不可轉譯。
改變定界字元的目的就是為了不要轉譯「斜線」,如果又轉譯那麼在 BRE 不會出錯,ERE 會出錯 (參閱: 測試轉譯斜線)。? + | ( ) { }
上述特殊字元作為文字字元時,在 BRE 不需轉譯,但在 ERE 需要轉譯。參閱:測試「特殊字元」轉譯。
-
作為 BRE 文字字元時,不需要 (也不可) 轉譯,但作為匹配字元時需轉譯。
-
作為 ERE 文字字元時,需轉譯,但作為匹配字元時,不需要 (也不可) 轉譯。
sed 的指令碼如果是使用單引號 (
'
),而文字中有單引號時,那麼 bash 要轉譯文字字元為\'
,反之如果是雙引號 ("
) 則要轉譯\"
。- bash 在雙引號時,除了轉譯
"
也要注意字元\
$
(作為文字字元,並非引用變數) 也需要跳脫字元 -
echo "\" \\ \$"
執行結果:" \ $
當文字內容含「特殊字元」時,需注意 bash 是否正確,如將
$'pattern'
替換為$'replacement'
echo "\$'pattern'" | sed "s/\$'pattern'/\$'replacement'/"
'replacement'
結果無誤,但實際上是錯的
顯示整段命令:echo "\$'pattern'" \| sed "s/\$'pattern'/\$'replacement'/"
'pattern' | sed s/$'pattern'/$'replacement'/ (1)
1 沒有轉譯 $
,但剛好 BRE 可在不需要轉譯的情況下執行,但如果改為 ERE 則會出錯。在 測試「特殊字元」轉譯 如下specChar='$' 3.14159 (BRE 轉譯) 3.14159 (BRE 不轉譯) 3.14159 (ERE 轉譯) 3$14 (ERE 不轉譯)
在寫 bash 時,
echo
會記得轉譯$
,但;當重點放在 sed 轉譯特殊字元時,往往會忽略 (忘記) 了 bash 在雙引號 ("
) 時也需要轉譯\
$
。先顯示整段命令,確認 bash 無誤:echo "\$'pattern'" \| sed "s/\\\$'pattern'/\\\$'replacement'/"
執行結果:'pattern' | sed s/\$'pattern'/\$'replacement'/
以 BRE ERE 執行命令:echo "\$'pattern'" | sed "s/\\\$'pattern'/\\\$'replacement'/" &&\ echo "\$'pattern'" | sed -E "s/\\\$'pattern'/\\\$'replacement'/"
-
- 匹配字元
-
- 字元
.
-
匹配一個任意字元。
- 字元
^
-
匹配開始位置。
- 字元
$
-
匹配結束位置。
- 字元
*
-
表示前置字元有任意個 (包含 0 個)。
如a*b
表示b
的前面有 0 個或多個a
,匹配b
、aaab
。而.*
則表示全部文字。 - 字元
?
-
表示前置字元有 0 個或 1 個。BRE 需要使用
\?
。
如a\?b
表示b
的前面有 0 個或 1 個a
,匹配b
、ab
,不匹配aab
。
?
作為 BRE 匹配字元時,需要前置跳脫字元 (\
),但作為文字字元時不可加入跳脫字元。
?
作為 ERE 匹配字元時,不需要 (也不可有) 跳脫字元,但作為文字字元時需要前置跳脫字元。 - 字元
+
-
表示前置字元有 1 個或多個,BRE 需要使用
\+
。
如a\+b
表示b
的前面有 1 個或多個a
,匹配ab
、aaab
,不匹配b
。 - 字元
|
-
表示指明兩項之間的一個選擇,
cat|dog
表示可以匹配cat
或者dog
,BRE 需使用\|
。將monkey
moose
隱藏:echo 'meerkat monkey moose mule' | sed 's/monkey\|moose/hide/g' &&\ echo 'meerkat monkey moose mule' | sed -E 's/monkey|moose/hide/g'
meerkat hide hide mule meerkat hide hide mule
- 字元
&
-
合乎匹配的文字。
前置任意字元的ats
,加上中括號echo 'Bats and cats.' | sed 's/.ats/\[&\]/g'
[Bats] and [cats].
- 字元
[]
-
中括號中可以包含表示字元集 (character sets) 的表示式,使用方法大概有如下幾種: [0-9]
表示 0-9 字元中的一個。
[0-9.]
表示數字和小數點。
[a-z]
表示 a-z 字元中的一個。
[A-Z]
表示大寫字母。
[a-zA-Z0-9]
大小寫字母和數字。
[abc]
表示字元 a 或者字元 b 或者字元 c。
[^0-9]
表示非數字的字元,
^
表示取反意思,只能放在中括號的開始處才有意義。[-az]
表示字元 - 或者字元 a 或者字元 z,注意與
[a-z]
的區別,因為 - 字元沒有放在 a 和 z 之間。將動物前置 mo mu 隱藏 (找出前置 m 後接 [ou] 再接任意個 [a-z]*):echo 'meerkat monkey moose mule' | sed 's/m[ou][a-z]*/hide /g' &&\ echo 'meerkat monkey moose mule' | sed -E 's/m[ou][a-z]*/hide /g'
meerkat hide hide hide meerkat hide hide hide
將參數改名,匹配開始字元,任意個不等於「結束字元」的字元,再匹配結束字元echo 'show(abc)' | sed 's/([^)]*)/(def)/' &&\ echo 'show(abc)' | sed -E 's/\([^\)]*\)/\(def\)/'
show(def) show(def)
取代任意文字,要指定可取代那些字元;最好的方式是字元條件不等於 pattern 的結束字元 ( [^pattern]
)。- 字元
[[: :]]
-
sed 除了正規的字元集外還支援命名字元類 (named character classes),命名類必須在兩個中括號內使用。
命名字元類的等效字元集如下: [[:alnum:]]
[A-Za-z0-9]
大小寫字母和數字。
[[:alpha:]]
[A-Za-z]
英文字母。
[[:blank:]]
[ \x09]
空格或製表字元 (Tab 鍵)。
[[:cntrl:]]
[\x00-\x19\x7F]
控制字元。
[[:digit:]]
[0-9]
數字。
[[:graph:]]
[!-~]
空白字元之外的 (可見) 字元。
[[:lower:]]
[a-z]
小寫字母。
[[:print:]]
[ -~]
可列印的字元(類似
[[:graph:]]
,但包括空白字元)。[[:punct:]]
[!-/:-@[-`{-~]
標點符號。
[[:space:]]
[ \f\n\r\t\v]
所有空白字元。
[[:upper:]]
[A-Z]
大寫字母。
[[:xdigit:]]
[0-9a-fA-F]
16 進制字元。
[^[:digit:]]
[^0-9]
表示非數字的字元,
^
表示取反意思,只能放在第二個中括號的開始處才有意義。
- 字元
- 字元
\
-
\a
Alert (警報) beep,嗶聲,等價於
\x07
和\cG
。\b
匹配「單詞」邊界。註:單詞為字母、數字或底線 (
_
)。\B
匹配非單詞邊界。(
\B
的匹配條件跟\b
相反。)\d
匹配數字 (含中文全型數字),等價於
[0-9]
。\D
匹配非數字,等價於
[^0-9]
。\f
匹配換頁字元,等價於
\x0c
和\cL
。\n
匹配換行字元,等價於
\x0a
和\cJ
。\r
匹配確認鍵,等價於
\x0d
和\cM
。\s
匹配空白字元;包括空格 (含中文全型空格)、換頁字元、製表字元等等,等價於
[ \f\n\r\t\v]
。\S
匹配非空白字元,等價於
[^ \f\n\r\t\v]
。\t
匹配一個製表字元,等價於
\x09
和\cI
。\v
匹配一個垂直製表字元,等價於
\x0b
和\cK
。\w
匹配「單詞」字元,等價於
[A-Za-z0-9_]
。\W
匹配非單詞的字元,等價於
[^A-Za-z0-9_]
。\cx
匹配控制字元 x,例如,
\cM
為一個 Ctrl+M 或確認鍵。\xnn
16 進制數值 nn,如
\x0a
為換行。\dnum
10 進制數值 num,如
\d10
為換行。\u
在 sed 中是將字元轉成大寫,並非作為 Unicode 編碼,參閱:特殊序列。
匹配「單詞」邊界 (
\b
)。將邊界以中括號標示echo 'at attach cattle cat' | sed -e 's/\b/\[&\]/g' &&\ echo 'at attach cattle cat' | sed -E 's/\b/\[&\]/g'
[]at[] []attach[] []cattle[] []cat[] []at[] []attach[] []cattle[] []cat[]
邊界是一個抽象的匹配,在邊界時條件為吻合。
先匹配文字at
再匹配邊界\b
echo 'at attach cattle cat' | sed 's/at\b/&\[\]/g' &&\ echo 'at attach cattle cat' | sed -E 's/at\b/&\[\]/g'
at[] attach cattle cat[] at[] attach cattle cat[]
匹配文字
at
條件之後要為邊界才為吻合。先匹配邊界\b
再匹配文字at
echo 'at attach cattle cat' | sed 's/\bat/\[\]&/g' &&\ echo 'at attach cattle cat' | sed -E 's/\bat/\[\]&/g'
[]at []attach cattle cat []at []attach cattle cat
邊界條件匹配後,再匹配文字
at
才為吻合。
無邊界文字,匹配「邊界」。echo '12345678' | sed 's/\b/\[&\]/g' []12345678[]
在文字的前後邊界時條件為吻合。
千位分隔符號,在一段連續的數字中,由右方開始算起,每隔三位數加進一個逗號。
在數字右方 (邊界),開始算起接連三個數字,加入一個逗號。
用 sed 的說明:在匹配三個數字 ([0-9]{3}
) 後要接「邊界」(\b
)。匹配三個數字 ([0-9]{3}
) 後要接「邊界」(\b
)echo '12345678' | sed 's/[0-9]\{3\}\b/\[&\]/' 12345[678]
上述雖然正確,但如果數字為123
也會合乎條件,匹配式有錯。echo '123' | sed 's/[0-9]\{3\}\b/\[&\]/' [123]
條件需再加上,開始的「非邊界」。
在「非邊界」之後,接三個數字,在三個數字之後要接「邊界」。條件是
-
非邊界
/B
-
三個連續數字 [0-9]{3}
-
邊界
/b
echo '12345678' | sed 's/\B[0-9]\{3\}\b/\[&\]/' &&\ echo '12345678' | sed -E 's/\B[0-9]{3}\b/\[&\]/' &&\ echo '123' | sed 's/\B[0-9]\{3\}\b/\[&\]/' &&\ echo '123' | sed -E 's/\B[0-9]{3}\b/\[&\]/'
12345[678] 12345[678] 123 123
註:接下來要「分支」的動作,才能完成
12,345,678
在 \B
\b
之間的匹配,可當做是由後面 (右邊) 開始,向前面 (左邊) 匹配。
「單詞」有那些?
測試「單詞」邊界:echo "abc +-*/=. 123 _" | sed 's/\b/X/g'
單詞邊界結果:XabcX +-*/=. X123X X_X
單詞為字母、數字或底線 (
_
)。
匹配換行
\n
,sed 需要使用-z
選預。將換行替換為,
seq 3 | sed -z 's/\n/,/g'
如何處理 Unicode 編碼?
如Σ
的 Unicode 編碼為\u03a3
。echo -n Σ | iconv -t JAVA \u03a3
-
直接採用 Unicode 字元。
-
由
echo -n Σ | od -tx1
或echo -n Σ | hexdump -C
轉換成 16 進位字元 (ce
、a3
)。 -
以 bash echo 來轉換如
'$(echo -ne '\u03a3')'
。 -
以 bash 轉換如
'$'\u03a3''
echo Σ | sed 's/Σ/X/' &&\ echo Σ | sed 's/\xce\xa3/X/' &&\ echo Σ | sed 's/'$(echo -ne '\u03a3')'/X/' &&\ echo Σ | sed 's/'$'\u03a3''/X/'
X X X X
-
- 字元
(
pattern)
-
表示分組「Group」,在
(
)
之間為匹配樣板 (pattern),BRE 需使用\(
及\)
。可以通過回撥引數\1
、\2
、\3
至最大值為\9
來表示分組匹配內容。只列印匹配分組樣板monkey
:echo 'mule monkey moose' | sed 's/.*\(monkey\).*/\1/' &&\ echo 'mule monkey moose' | sed -E 's/.*(monkey).*/\1/'
monkey monkey
將參數 b a 互換 a1 b2echo 'add(b, a)' | sed 's/add(\([^,]\+\), *\([^)]\+\)/add(\21, \12/' &&\ echo 'add(b, a)' | sed -E 's/add\(([^,]+), *([^\)]+)/add(\21, \12/'
add(a1, b2) add(a1, b2)
回撥引數最大為
\9
,\21
是指回撥第2
組再加上數字1
。 - 字元
{
n,m}
-
{n}
匹配 n 次。如
o{2}
不能匹配fox
中的一個o
,但是能匹配google
中的兩個o
。{n,}
至少匹配 n 次。如
o{2,}
不能匹配fox
中的一個o
,但能匹配goooogle
中的所有o
。
o{1,}
等價於o+
,o{0,}
則等價於o*
。{n,m}
至少匹配 n 次且最多匹配 m 次。如
o{1,3}
,將匹配goooogle
前三個o
。
o{0,1}
等價於o?
BRE 需使用
\{n,m\}
。匹配一個或多個小寫 o,替換為一個大寫 O:echo 'meerkat monkey moose mule' | sed 's/o\{1,\}/O/g' &&\ echo 'meerkat monkey moose mule' | sed 's/o\+/O/g' &&\ echo 'meerkat monkey moose mule' | sed -E 's/o{1,}/O/g' &&\ echo 'meerkat monkey moose mule' | sed -E 's/o+/O/g'
meerkat mOnkey mOse mule meerkat mOnkey mOse mule meerkat mOnkey mOse mule meerkat mOnkey mOse mule
- 字元
- 字元
(
及)
在 BRE (基本正規表示法) 及 ERE (延伸正規表示法) 的差異 -
文字字元
(
及)
在 BRE 不是特殊字元不需要轉譯。如替換 (Hello) 取代成 hi:echo '(Hello)' | sed 's/(Hello)/hi/' hi
如果轉譯成\(
及\)
,則變成 BRE 分組「Group」。echo '(Hello)' | sed 's/\(Hello\)/hi/' (hi)
但為什麼會有這樣的結果?
「分組」取得分組樣板Hello
,將其分組樣板替換為hi
,
原始文字 (Hello) 為 (「分組樣板」),將其「分組樣板」替換 hi 其結果為 (hi)。文字字元(
及)
在 ERE 需要轉譯:echo '(Hello)' | sed -E 's/\(Hello\)/hi/' hi
不轉譯(
及)
,則為 ERE 分組「Group」。echo '(Hello)' | sed -E 's/(Hello)/hi/' (hi)
sed 指令 (script)
sed 程序由一個或多個 sed 指令 (script) 組成,由多個 -e
選項傳入或者執行 -f
指定的指令檔。
[選擇行號] 命令 [選項]
- 多指令語法
-
指令的範例是將
2
替換為2B
、3
替換為3C
。多指令使用-e
選項seq 5 | sed -e 's/2/2B/' -e 's/3/3C/' (1)
1 -e
之前要空格,-e
之後可不需要空格。使用分號 (;
)seq 5 | sed 's/2/2C/; s/3/3C/' (1)
1 分號之後可不需要空格。 使用換行seq 5 | sed 's/2/2B/ s/3/3C/ '
使用檔案 (-f
選項):cat > script.sed << EOF s/2/2B/ s/3/3C/ EOF seq 5 | sed -f script.sed
- sed 管道
-
當讀取跟輸出的檔案相同時,如果以下列方式執行:
sed command $File | sed command > $File (1) cat $File | sed command | sed command > $File (1)
1 將得到一個空的 $File,原因是在建立管道時,輸出管道 > $File
會先執行將建立一個空的 $File。可使用臨時檔案來解決此問題:sed command $File | sed command > tmpFile mv tmpFile $File cat $File | sed command | sed command > tmpFile mv tmpFile $File
選擇行號 (Addressing)
|
指定「行號 (number 數字)」僅匹配該「行號」。 |
|
由 first 行號 (數字) 開始,間隔 ( |
|
匹配最後一行 |
|
匹配正規表示式 regexp 的「行」。 |
|
同樣是匹配正規表示式 regexp,但允許使用與 |
|
regexp 不區分大小寫 |
|
多行模式空間採用修飾字元 |
|
上述可以採用逗號 ( |
|
行號 0 可以用在地址規範中,例如 |
|
由 addr1 行開始,再接著往下數 N 行,也就是 addr1 至 addr1+N 行。 |
|
由 addr1 行開始至 ( |
- number
-
第 2 行執行列印
seq 3 | sed -n '2 p' (1) 2
1 sed 使用 -n
選項 (不自動輸出),由p
(列印) 命令來輸出,另外2 p
中間可不需要空格字元。- first~step
-
從第 2 行開始,每隔 (
~
) 3 行,執行列印seq 9 | sed -n '2~3 p' 2 5 8
- regexp
-
找出
B
行,執行列印printf '%s\n' 1A 2B 3C | sed -n '/B/ p' &&\ printf '%s\n' 1A 2B 3C | sed -n '/b/I p' 2B 2B
找出不存在的F
,執行列印printf '%s\n' 1A 2B 3C | sed -n '/F/ p'
沒有輸出。
- \%regexp%
-
採用定界字元
%
及#
,不需轉譯/
。找出含字元/
的行,執行列印。printf '%s\n' 1A 2/ 3C | sed -n '\%/% p' &&\ printf '%s\n' 1A 2/ 3C | sed -n '\#/# p' &&\ printf '%s\n' 1A 2/ 3C | sed -n '/\// p' 2/ 2/ 2/
$
需要轉譯成\$
,表示式\%regexp%
是允許使用與/
不同的定界字元,並不是不需要「轉譯」。找出$
行,執行列印printf '%s\n' 1A 2$ 3C | sed -n '\%\$% p' &&\ printf '%s\n' 1A 2$ 3C | sed -n '/\$/ p' 2$ 2$
- /regexp/M
-
模式空間只有一行時,能匹配
^
、$
。列印開頭 (^
) 之後為2
或者2
在結束 ($
) 之前的行。seq 3 | sed -n '/^2/ l' &&\ seq 3 | sed -n '/2$/ l'
2$ 2$
但在多行時,無法匹配
2
,因為2
不在整個資料的開頭之後或結束之前。下列將無輸出seq 3 | sed -n 'N;N; /^2/ p' &&\ seq 3 | sed -n 'N;N; /2$/ p'
採用修飾字元
M
,則能匹配每行的^
、$
。匹配第 2 行的^
、$
:seq 3 | sed -n 'N;N; /^2/M l' &&\ seq 3 | sed -n 'N;N; /2$/M l'
1\n2\n3$ 1\n2\n3$
- n,m
-
第 2 行 至(
,
) 第 4 行執行列印seq 100 | sed -n '2,4 p' 2 3 4
第 4 行 至(,
) 第 2 行,只有第 4 行執行列印 (行號 4 至行號 2,只有行號 4 合乎)printf '%s\n' 1A 2B 3C 4D 5E | sed -n '4,2 p' 4D
第 D 行 至(,
) 第 2 行執行列印,只有 D 行執行列印 (D 行號為 4 至行號 2,只有行號 4 合乎)printf '%s\n' 1A 2B 3C 4D 5E | sed -n '/D/,2 p' 4D
第 2 行 至(,
)D
行執行列印printf '%s\n' 1A 2B 3C 4D 5E | sed -n '2,/D/ p' 2B 3C 4D
第 4 行 至(,
)B
行執行列印,regexp 沒有匹配B
,列印 第 4 行至最後一行 (regexp 沒有匹配,則範圍由第一個位置至最後一行)。printf '%s\n' 1A 2B 3C 4D 5E | sed -n '4,/B/ p' 4D 5E
第 1 行 至(,
)A
行執行列印,regexp 沒有匹配A
(匹配開始位置是第一個位置之後),列印 第 1 行至最後一行。printf '%s\n' 1A 2B 3C 4D 5E | sed -n '1,/A/ p' 1A 2B 3C 4D 5E
- 0,regexp
-
第 0 行 至(
,
)A
行執行列印printf '%s\n' 1A 2B 3C | sed -n '0,/A/ p' 1A
第 0 行 至(,
) 不存在F
行執行列印,regexp 沒有匹配,列印全部。printf '%s\n' 1A 2B 3C | sed -n '0,/F/ p' 1A 2B 3C
- addr1,+N
-
從第 2 行開始,再接著往下數 (
+
) 3 行,也就是 2 至 5 行執行列印seq 100 | sed -n '2,+3 p' 2 3 4 5
- addr1,~N
-
由第 4 行開始 至(
,
) 下一個倍數 (~
) 3 的行號,也是 4 至 6 執行列印。seq 100 | sed -n '4,~3 p' 4 5 6
選擇行號「分組」表示式
選擇行號的 BRE 分組功能 \(
regexp\)
,ERE 需使用 (
regexp)
,所選取的內容為兩組相同;分組匹配的內容跟回撥內容 (\1
) 相同,如匹配內容為 9
回撥內容亦為 9
則匹配 99
的行。
seq 87 110 | sed -En '/(.)\1/p'
88 99 100 110
\19
,回撥引數最大為 \9
,\19
是指回撥第 1
組再加上字元 9
。seq 100 400 | sed -En '/(.)\19/p'
119 229 339
seq 9100 9400 | sed -En '/^9(.)\19$/p'
9119 9229 9339
^
) 及 匹配結束位置 ($
) 說明:-
/(.)\1/
匹配二個相同字元。 -
/^(.)\1/
匹配開始位置^
,開始的字元再接續一個相同的字元。 -
/(.)\1$/
匹配結束位置$
,回撥匹配,最後的字元要跟前一個字元相同。 -
/^(.)\1$/
同時匹配開始及結束,在匹配一個字元的情況,只有兩個相同的字元合乎匹配。
seq 87 110 | sed -En '/^(.)\1/p'
88
99
110
seq 87 110 | sed -En '/(.)\1$/p'
88
99
100
seq 87 111 | sed -En '/^(.)\1$/p'
88
99
若表示式中可匹配多個數量如 *
、?
,以 /(.*),\1/
為例,將兩組文字以字元 ,
區分。
若分組表示式無其他條件,則分組匹配內容往往是 0 個字元,則匹配有字元 ,
的行。
/(.*),\1/
匹配有字元 ,
的行printf '%s\n' 1,1 12,123 321,21 12345 | sed -En '/(.*),\1/p' 1,1 12,123 321,21
/^(.*),\1/
匹配第一組開始的文字跟第二組開始的文字。printf '%s\n' 1,1 12,123 321,21 | sed -En '/^(.*),\1/p'
1,1
12,123
/(.*),\1$/
回撥匹配第二組文字跟第一組文字 (字元 ,
之前)。printf '%s\n' 1,1 12,123 321,21 | sed -En '/(.*),\1$/p'
1,1
321,21
/^(.*),\1$/
同時匹配開始及結束,匹配兩組相同的文字。printf '%s\n' 1,1 12,123 321,21 | sed -En '/^(.*),\1$/p'
1,1
sed 基本命令
|
新增文字,在行後新增文字 (文字在下一行)。 |
|
取代文字,用文字取代行。 |
|
刪除。 |
|
插入文字,在行之前插入文字 (文字在上一行)。 |
|
以明確形式列印 (列印控制字元)。 |
|
讀取下一行。 |
|
列印。 |
|
離開。 |
|
讀取檔案。 |
|
替換 (搜尋並替換)。 |
|
寫到檔案。 |
|
轉換字元。 |
|
列印行號。 |
a
(新增)、i
(插入)
- a text
-
在行後新增一行文字,輸入的文字直到換行。自動忽略
a
命令後跟文字間的空格。在第二行後新增 hello:seq 3 | sed '2a hello'
1 2 hello 3
如果換行要接續則輸入「行接續字元
\
(反斜線)」。在第二行後新增一行 hello 再接續 world:seq 3 | sed '2a hello\ world ' (1)
1 亦可採用「 \n
換行」如seq 3 | sed '2a hello\nworld'
1 2 hello world 3
在第二行後新增 hello,在第三行新增 world:seq 3 | sed '2a hello 3a world '
1 2 hello 3 world
- i text
-
在行前插入一行文字,輸入的文字直到換行。自動忽略
i
命令後跟文字間的空格。在第二行前插入 hello:seq 3 | sed '2i hello'
1 hello 2 3
如果換行要接續則輸入「行接續字元
\
(反斜線)」。在第二行前插入一行 hello 再接續 world:seq 3 | sed '2i hello\ world ' (1)
1 亦可採用「 \n
換行」如seq 3 | sed '2i hello\nworld'
1 hello world 2 3
在第二行前插入 hello,在第三行前插入 world:seq 3 | sed '2i hello 3i world '
1 hello 2 world 3
- a\
text -
在行後新增文字,在新行新增文字,直到換行。忽略
a\
之間的空格。在第二行後新增 hello (前置一個空格):seq 3 | sed '2a\ hello'
1 2 hello 3
如果換行要接續則輸入「行接續字元\
(反斜線)」:seq 3 | sed '2a\ hello\ world s/./x/' (1)
1 本例再增加替換命令,替換 (一行只有) 一個任意字元為 x
。x x hello world x
a\
命令和文字可以分為兩個-e
引數,使編寫指令碼更加容易:seq 3 | sed -e '2a\' -e ' hello\nworld' -e 's/./x/'
- i\
text -
在行前插入文字,在新行輸入文字,直到換行。忽略
i\
之間的空格。在第二行前插入 hello (前置一個空格):seq 3 | sed '2i\ hello'
1 hello 2 3
如果換行要接續則輸入「行接續字元\
(反斜線)」:seq 3 | sed '2i\ hello\ world s/./x/'
x hello world x x
i\
命令和文字可以分為兩個-e
引數,使編寫指令碼更加容易:seq 3 | sed -e '2i\' -e ' hello\nworld' -e 's/./x/'
c
(取代)
用文字取代行,輸入的文字直到換行。自動忽略 c
命令後跟文字間的空格。
seq 3 | sed '2c hello'
1 hello 3
如果換行要接續則輸入「行接續字元 \
(反斜線)」。
seq 3 | sed '2c hello\
world (1)
'
1 | 亦可採用「\n 換行」如 seq 3 | sed '2c hello\nworld' |
1 hello world 3
seq 3 | sed '2c hello
3c world
'
1 hello world
- c\
text -
用文字取代行,輸入的文字直到換行。忽略
c\
之間的空格。在第二行取代成 hello (前置一個空格):seq 3 | sed '2c\ hello'
1 hello 3
如果換行要接續則輸入「行接續字元
\
(反斜線)」。seq 3 | sed '2c\ hello\ world s/./x/'
x hello world x
c\
命令和文字可以分為兩個-e
引數,使編寫指令碼更加容易:seq 3 | sed -e '2c\' -e ' hello\nworld' -e 's/./x/'
x hello world x
n
(讀取下一行)
seq 10 | sed -n 'n;n;p'
sed 先讀取第 1 行,再讀取 2 行,第 3 行列印。下一個循環 (cycle),由第 4 行開始,讀取 2 行,第 6 行 列印,再次執行下一個循環。
3 6 9
q
、Q
(離開)
離開 sed 不再處理任何命令或輸入。
- 命令格式
-
q
[exit-code]Q
[exit-code]
Q
命令和 q
一樣,但 Q
離開時不會列印。
seq 3 | sed 'n;q'
1 2
seq 3 | sed 'n;q255' ; echo $? (1)
1 | 由 echo $? 列印回傳代號。 |
1 2 255
/etc/passwd
的前 10 行sed '10q' /etc/passwd
s
(替換)
替換命令格式 s/pattern/replacement/flags
|
全域性更改 |
|
不區分大小寫。 |
|
多行模式 (multi-line mode)。 |
|
列印 |
|
寫入檔案 (多個 flag 時,需放在最後) |
|
第 number 次匹配時,執行替換。 |
flags 可用 (不定數量的) 空格字元區分。
- flags 示例
-
number
-
取代 a 為 X:
echo BAnana | sed 's/a/X/' BAnXna
取代第 2 個 a 為 X (flagsnumber
為 2):echo BAnana | sed 's/a/X/2' BAnanX
g
-
以 flags
g
(全域性更改) 全部取代 a 為 X:echo BAnana | sed 's/a/X/g' BAnXnX
i, I
-
以 flags
g
及i
(不區分大小寫) 取代 a 為 X:echo BAnana |sed 's/a/X/gi' BXnXnX
p
-
sed 採用
-n
命令列選項不自動輸出:echo BAnana |sed -n 's/a/X/'
無輸出
由s
命令採用 flagsp
(列印) 輸出:echo BAnana |sed -n 's/a/X/p' BAnXna
w
-
由
s
命令採用 flagsw
(寫入) 到標準輸出:echo BAnana |sed -n 's/a/X/w /dev/stdout' BAnXna
m, M
-
在說明多行模式 (multi-line mode) 之前,先準備好多行的文字內容。
sed 先讀取第 1 行, 執行 2 次命令
N
(讀取下一行),讀取後的「文字內容」會有 3 行。
註:「文字內容」稱為「模式空間 (pattern space)」。seq 3 | sed 'N;N'
1 2 3
s
替換命令預設行為-
sed 預設行為將模式空間中所有的資料一起處理,整個資料只有一個開始 (
^
) 和結束($
),而匹配一個任意字元 (.
) 也是整個資料一起匹配。替換「開始 (^
)」為^
,替換「結束 ($
) 」為$
seq 3 | sed 'N;N; s/^/\^/g; s/$/\$/g'
^1 2 3$
任意數量的字元 (.*
) 加上中括號seq 3 | sed 'N;N; s/.*/\[&\]/g'
[1 2 3]
s
替換命令多行模式-
在多行模式 (multi-line mode) 下,
^
、$
表示每一行的開始和結束,而.
只會匹配同一行。替換「開始 (^
)」為^
,替換「結束 ($
) 」為$
seq 3 | sed 'N;N; s/^/\^/mg; s/$/\$/mg'
^1$ ^2$ ^3$
任意數量的字元 (.*
) 加上中括號seq 3 | sed 'N;N; s/.*/\[&\]/mg'
[1] [2] [3]
|
將「替換文字 (replacement)」轉成小寫,直到 |
|
將第一個字元轉為小寫。 |
|
將替換轉成大寫,直到 |
|
將第一個字元轉成大寫。 |
|
停止 (由 |
\U
示例-
匹配前置任意字元的 at,將合乎匹配的文字 (
&
) 轉成大寫 (\U
)。echo 'bat monkey and cat' | sed 's/.at/\U&/g'
BAT monkey and CAT
\u
示例-
匹配前置任意字元的 at,將合乎匹配的文字 (
&
) 第一個字改成大寫(\u
)。echo 'bat monkey and cat' | sed 's/.at/\u&/g'
Bat monkey and Cat
y
(轉換字元)
y/原始字元集/目的字元集/
替原始字元集的個數和目的字元集個數必須相等,字元集內每個字元一一對應。
a-j
至 0-9
:echo hi mary | sed 'y/abcdefghij/0123456789/' 78 m0ry
l
(明確形式列印)
- 明確形式列印
-
無法列印的字元 (如換行
\n
) 和字元\
以 C 風格的形式轉譯;超出長度的尾端會以「接續字元\
」拆分,末尾會標示$
。
註:字元$
是由命令l
明確表達,該字元實際上並不存在。
可由命令選項 l N
或命令列選項 sed -l N
、sed --line-length=N
指定輸出最大長度 N。
echo -e 'Hello\tworld' | sed -n 'l'
Hello\tworld$
echo -e 'Hello\tworld' | sed -n 'l8'
-l
限制長度 8echo -e 'Hello\tworld' | sed -l8 -n -e 'l'
Hello\t\ (1) world$
1 | 當長度不足時,尾端會列印「接續字元 \ 」。 |
下列可將 將換行替換為 ,
seq 3 | sed -z 's/\n/,/g'
但為什麼? 因為命令列選項 -z
會將所有的換行,變成一行文字。
z
的行為seq 3 | sed -zn 'l' (1)
1 | 由於執行了明確列印 (l ),以命令列選項 (-n ) 禁止「預設列印」,避免混淆。 |
1\n2\n3\n$
sed 進階命令
在說明進階命令之前,先說明「模式空間 (pattern space
)」。
sed 的預設動作為一次讀取一行到「模式空間」,然後執行指令,接著處理下一行;繼續「循環 (cycle)」直到檔案結束 (EOF)。
d
刪除命令是指刪除「模式空間」,p
列印命令是指列印「模式空間」,sed 的「預設列印」(命令列選項無 -n
) 也是列印 (在處理所有指令後剩下的) 「模式空間」。
- sed 進階命令
-
d
刪除模式空間,然後重啟循環 (cycle)。
D
刪除模式空間內的第一行,並以模式空間 (刪除後) 的結果「重啟指令 (script)」。
註:如果 (刪除前的) 模式空間不含換行,則為一般循環跟d
命令相同 (會讀取新行)。n
(讀取) 下一行複製至模式空間 next (copy),「預設列印」模式空間。
N
(讀取) 下一行新增至模式空間 Next (append)。
p
p (小寫) 列印模式空間。
P
P (大寫) 列印模式空間內的第一行。
q
離開,「預設列印」(目前的) 模式空間。
Q
離開 (不列印)。
z
清除模式空間。
{}
命令組,一次執行多個命令,命令組格式為
{ 命令 [;命令] }
。#
註解
!
否定 (反動作)
註:命令列有
-n
選項時,則不會「預設列印」。- 進階命令補充
-
D
命令-
刪除模式空間內的第一行,剩餘第二行(含以後),若模式空間只有一行則全部刪除,另一種說法是「刪除模式空間的內容直到第一個換行字元,若無換行時則刪除全部」。
本節中將D
的後續動作稱為「重啟指令」(重新執行指令),不採用通用的說法「重啟循環」,避免混淆。重啟指令時,sed 並不會讀取新的輸入行,而是按照指令執行動作。 n
命令-
讀取下一行複製至模式空間,先前的「模式空間」將會消失,該命令可「預設列印」先前 (未讀取前) 的「模式空間」。
N
命令-
讀取下一行新增至模式空間,另一種說法是「先新增換行至模式空間,再將讀取行新增至模式空間」。
模式空間的結果為:「目前 (上次) 的模式空間」 +\n
+ 讀取行 (本次讀取的模式空間)」。 P
(大寫) 命令-
列印模式空間內的第一行,若模式空間只有一行也會列印,另一種說法是「列印模式空間內的第一個字直到換行字元,若無換行則列印全部」。
seq 5 | sed 'n;l;d'
1 2$ 3 4$ 5
- 流程說明
-
-
在每個循環的開始,sed 讀取一行至模式空間 (在第一循環為
1
)。 -
命令
n
「預設列印」上次模式空間(在第一循環為 1),命令n
讀取下一行至模式空間 (在第一循環為2
)。 -
命令
l
明確列印模式空間時加入尾端標示 (在第一循環為 2$)。 -
命令
d
重啟循環。 -
在下一個循環中,sed 讀取一行至模式空間 (例如
3
),命令n
讀取下一行至模式空間 (例如4
)。
-
seq 5 | sed -n 'n;p;d'
2 4
在上述的「流程說明」步驟說明如下
|
n;p
為下一行列印,那麼列印 3 倍數行則為「下一行再下一行然後列印」,指令為 n;n;p
(亦可採用 選擇行號 如 0~3 p
)。
列印單數行為「先列印再讀取下一行」,指令為 p;n
(或採用選擇行號的 1~2 p
)。
--debug
選項,可得知程序情況seq 5 | sed -n 'n;p' --debug
SED PROGRAM: n p INPUT: 'STDIN' line 1 PATTERN: 1 COMMAND: n PATTERN: 2 COMMAND: p 2 END-OF-CYCLE: INPUT: 'STDIN' line 3 PATTERN: 3 COMMAND: n PATTERN: 4 COMMAND: p 4 END-OF-CYCLE: INPUT: 'STDIN' line 5 PATTERN: 5 COMMAND: n (1) END-OF-CYCLE:
1 | 列印雙數行在列印第 4 行後的循環;在第 5 行執行 n;p 時,在執行 n 命令之後已經 EOF ,sed 會中斷循環並結束。 |
多行處理
printf '%s\n' a b c | sed = | sed -e 'N; s/\n/ /'
1 a 2 b 3 c
-
第一個 sed,先將每一行,列印行號 (
=
) 成為二行,行號在第一行,原始內容的第一行變成第二行。 -
第二個 sed,以命令
N
將兩行合併成一行,兩行中間為換行 (\n
),再以命令s
將換行替換為空格。
N; s/\n/ /
流程說明-
-
在每個循環的開始,sed 讀取一行至模式空間 (在第一循環為
1
)。 -
命令 N 讀取下一行 (第一循環為
a
),新增至模式空間 (第一循環為1
、\n
、a
)。 -
命令
s
將換行替換為空格 (第一循環為1 a
),執行後「預設列印」1 a。 -
非檔案結束 (EOF) 時繼續循環。
-
在下一個循環中,sed 讀取一行至模式空間 (例如
2
),命令N
讀取下一行 (例如b
),新增至模式空間 (例如2
、\n
、b
)。
-
seq 5 | sed 'N;l;D'
1\n2$ 2\n3$ 3\n4$ 4\n5$ 5
-
sed 將第一行讀入模式空間(即為
1
)。 -
在每個程序的開始,命令
N
新增至模式空間(第一個流程即為1
、\n
、2
)。 -
命令
l
列印模式空間的內容 (第一個流程即為 1\n2$)。 -
命令
D
刪除模式空間內的第一行(在第一個流程結束時模式空間留下2
)。
然後「重啟程序」 (並不會讀取新行,由第 2 步驟開始執行)。 -
在下一個流程中,命令
N
新增至模式空間(例如2
、\n
、3
)。 -
整個程序只有一個循環,循環結束時模式空間留下 5。
printf '%s\n' 1A 2B 2B 3C | sed -n '$!N; /^\(.*\)\n\1$/!P; D' &&\
printf '%s\n' 1A 2B 2B 3C | sed -En '$!N; /^(.*)\n\1$/!P; D'
1A 2B 3C 1A 2B 3C
printf '%s\n' 1A 2B 2B 3C | sed -n '$!N; /^\(.*\)\n\1$/!l; D'
1A\n2B$ 2B\n3C$ 3C$
-
sed 將第一行讀入模式空間(即為
1A
)。 -
在每個程序的開始,命令
$!N
在非最後行時新增至模式空間(第一個流程即為1A
、\n
、2B
)。 -
/^\(.*\)\n\1$/
將兩組文字以\n
區分,匹配兩組相同文字的「行號」,!l
行號不匹配時執行明確列印(第一個流程列印1A\n2B$
,若命令為P
則列印1A
)。 -
命令
D
刪除模式空間內的第一行(在第一個流程結束時模式空間留下2B
),然後「重啟程序」。 -
在第二個流程中命令
$!N
新增模式空間(例如2B
、\n
、2B
),行號匹配不執行!l
,命令D
(模式空間留下2B
)。 -
在第三個流程中命令
$!N
新增模式空間(例如2B
、\n
、3C
),行號不匹配執行!l
(第三個流程列印2B\n3C$
),命令D
(模式空間留下3C
)。 -
在第四個流程中,已為最後一行不執行
$!N
(模式空間為3C
),行號不匹配執行!l
(第四個流程列印3C$
)。 -
執行命令
D
時,模式空間不含換行字元為一般循環並且清除模式空間,sed 結束程序。
(
cat << EOF
Name:John
Year-old:38
Name:Marry
Year-old:43
Name:Helen
Year-old:38
EOF
) |
sed -n '/Name/ {
N
/Year-old:38/ !d
P
}'
Name:John Name:Helen
-
/Name/
匹配行號Name
。 -
N
新增模式空間(第一個流程即為Name:John
、\n
、Year-old:38
)。 -
/Year-old:38/
匹配行號年齡為 38,若不是則執行d
重啟循環。 -
P
列印模式空間的第一行(第一個流程列印Name:John
)。 -
在下一個循環中,年齡為 43,行號不匹配,執行
d
重啟循環。
空間操作
|
將模式空間複製到保持空間 hold (copy)。 |
|
將模式空間新增至保持空間 Hold (append)。 |
|
將保持空間複製到模式空間 get pattern space (copy)。 |
|
將保持空間新增至模式空間 Get pattern space (append)。 |
|
交換空間 (交換保持空間和模式空間互換) exchange。 |
- 空間操作命令補充
-
H
命令-
將模式空間新增至保持空間,另一種說法是「新增換行至保持空間,再將模式空間新增至保持空間」。
保持空間的結果為:「目前 (上次) 的保持空間」 +\n
+ 模式空間」。 G
命令-
將保持空間新增至模式空間,另一種說法是「新增換行至模式空間,再將保持空間新增至模式空間」。
模式空間的結果為:「目前 (上次) 的模式空間」 +\n
+ 保持空間」。
echo -e '1\n\n3\n4\n5' | sed -n '/./{H;$!d}; x; l'
\n1$ \n3\n4\n5$
第一個表示式 /./{H;$!d}
對所有具值的 (非空) 行執行「命令組」,將 (當前的) 模式空間新增到保持空間,非最後一行時刪除模式空間並重新循環。
「選擇行號」後面只能接一個命令,採用「{}
命令組」,將多個命令「組合」成一個。
-
第 1 行具值,模式空間為
1
新增到保持空間 (H
) 為\n1
(保持空間初始為空,新增至下一行)。非最後行 ($!
),由d
刪除模式空間並重啟循環。 -
第 2 行是空行,第一個表示式不會執行動作。
再來 sed 執行交換空間 (x
),將保持空間 (\n1
) 跟模式空間 (NUL
) 互換,互換後;保持空間為NUL
,模式空間為\n1
。
再明確列印模式空間 (l
) 為 \n1$。 -
第 3 行具值,模式空間為
3
,命令H
新增保留空間後為\n3
(在前一步驟保持空間為NUL
),非最後行重啟循環。 -
第 4 行具值,模式空間為
4
,命令H
新增保留空間後為\n3\n4
,非最後行重啟循環。 -
第 5 行具值,模式空間為
5
,命令H
新增保留空間後為\n3\n4\n5
,最後行不重啟循環。 -
再來 sed 執行
x; l
輸出 \n3\n4\n5$ 後結束程序。
echo -e '1\n\n3\n4\n5' | sed '/./{H;$!d}; x; s/^/\nSTART-->/; s/$/\n<--END/'
START--> 1 <--END START--> 3 4 5 <--END
如何倒序?
採用 G
將保持空間新增至模式空間,當保持空間是前一行時,新增後則為反排。(先新增再保留)。
seq 3 | sed -n 'G;h;l' (1)
1 | 在測試 sed 的命令時,跟前例一樣;以 l 明確列印比較清楚。 |
1\n$ 2\n1\n$ 3\n2\n1\n$
但每次列印,並不正確。
seq 3 | sed -n 'G;h;$l'
3\n2\n1\n$
大致正確,但上述的第一行也加入換行 (因為是反排,所以是最後字元)。
seq 3 | sed -n '1! G; h; $l'
3\n2\n1$
seq 3 | sed -n '1h; 2,${G;h}; $l'
分支
分支 (branch),意思是跳躍 (jump) 或者是 go to。
- sed 分支命令
-
:label
定義 label 為一個或多個字母作為標籤。
b
(無條件) 分支。
t
s
命令合乎匹配時分支。T
s
命令不匹配時分支。b
、t
和T
命令後面可接標籤,命令跟標籤之間可為 0 個或多個空白。分支至標籤時依據指令執行動作,但如果省略標籤,則分支命令會重啟循環 (sed 的預設動作會讀取新的輸入行)。 - 千位分隔符號範例
-
確定替換命令 (
s
) 正確處理千位符號echo '12345678' | sed 's/\B[0-9]\{3\}\b/,&/' &&\ echo '12345678' | sed -E 's/\B[0-9]{3}\b/,&/' &&\ echo '123' | sed 's/\B[0-9]\{3\}\b/,&/' &&\ echo '123' | sed -E 's/\B[0-9]{3}\b/,&/'
12345,678 12345,678 123 123
以分支完成所有的千位符號echo '12345678' | sed ':X s/\B[0-9]\{3\}\b/,&/; t X' &&\ echo '12345678' | sed -E ':X s/\B[0-9]{3}\b/,&/; t X'
12,345,678 12,345,678
流程如下:-
第一次匹配
678
,模式空間為12345,678
,合乎匹配分支到 (t
) 標籤 X,繼續匹配。 -
第二次匹配
345
,模式空間為12,345,678
,合乎匹配分支到標籤 X 並繼續。 -
第三次不合乎匹配,不分支並結束程序。
以分支執行匹配條件錯誤範例 echo '12345678' | sed ':X s/[0-9]{3}\b/,&/; t X' --debug
流程如下:-
第 1 次匹配
678
,模式空間為12345,678
,合乎匹配分支到 (t
) 標籤 X,繼續匹配。 -
第 2 次匹配
345
,模式空間為12,345,678
,合乎匹配分支到標籤 X 並繼續。 -
第 3 次匹配
345
,模式空間為12,,345,678
,合乎匹配分支到標籤 X 並繼續。 -
第 4 次匹配
345
,模式空間為12,,,345,678
,合乎匹配分支到標籤 X 並繼續。 -
sed 一直在執行沒有結束,這表示了發生了「無窮迴圈 (infinite loop)」,可採用命令列選項
--debug
來偵錯。
由上述的第 3 次流程中已知,匹配條件有錯誤。當發生無窮迴圈時,應先確定替換命令 (
s
) 有正確處理。替換命令匹配條件錯誤 (參閱:正規表示法-邊界):echo ',345,' | sed 's/[0-9]{3}\b/,&/'
,,345,
-
將所有行合併至模式空間。
seq 3 | sed -n ':X; N; $! bX; l'
1\n2\n3$
-
:X
建立標籤X
-
N
下一行新增至模式空間 -
$!
非最後一行,bX
(無條件) 分支到標籤X
,繼續執行指令。
-z
seq 3 | sed -nz 'l'
1\n2\n3\n$
,
seq 3 | sed -z 's/\n/,/g' &&\
seq 3 | sed ':X; N; $!bX; s/\n/,/g'
1,2,3,1,2,3
讀寫命令 (rRwW)
|
讀取整個檔案,插入到輸出流中。 |
|
依次讀取檔案一行,插入到輸出流中。 |
|
將模式空間寫入檔案。 |
|
將模式空間內的第一行寫入檔案。 |
r
、R
-
在循環結束時或在讀取下一個輸入時,將檔案內容插入到輸出流中。
-
不會影響模式空間
-
一律列印,忽略命令列選項
-n
。 -
若無法讀取檔案,則將其視為一個空檔,並不會出現錯誤。
讀取整個檔案 (命令r
),如輸出/etc/passwd
3 次seq 3 | sed -n 'r /etc/passwd'
依次讀取檔案一行 (命令R
),如輸出/etc/passwd
前 3 行seq 3 | sed -n 'R /etc/passwd'
-
w
、W
-
開啟的檔案會不斷新增,直到 sed 命令結束。
將模式空間寫入 (命令w
) 到標準輸出seq 3 | sed -n 'N; N; w /dev/stdout'
1 2 3
將模式空間內的第一行寫入 (命令W
) 到標準輸出,如模式空間每次讀取 3 行:seq 9 | sed -n 'N; N; W /dev/stdout'
1 4 7
採用命令w
輸出 1 4 7。seq 9 | sed -n -e 'w /dev/stdout' -e 'n;n'
在檔案名稱之後的命令,必須使用選項
-e
分開表示式。
測試「特殊字元」轉譯
確定哪些「特殊字元」在 BRE、ERE 需要以跳脫字元 (\
) 轉譯。
specChar='a'
echo "3${specChar}14" \| sed -e "s/3\\${specChar}14/3\.14159/" &&\
echo "3${specChar}14" \| sed -e "s/3${specChar}14/3.14159/" &&\
echo "3${specChar}14" \| sed -E "s/3\\${specChar}14/3\.14159/" &&\
echo "3${specChar}14" \| sed -E "s/3${specChar}14/3.14159/"
3a14 | sed -e s/3\a14/3\.14159/ 3a14 | sed -e s/3a14/3.14159/ 3a14 | sed -E s/3\a14/3\.14159/ 3a14 | sed -E s/3a14/3.14159/
echo "3${specChar}14" | sed -e "s/3\\${specChar}14/3\.14159/" &&\
echo "3${specChar}14" | sed -e "s/3${specChar}14/3.14159/" &&\
echo "3${specChar}14" | sed -E "s/3\\${specChar}14/3\.14159/" &&\
echo "3${specChar}14" | sed -E "s/3${specChar}14/3.14159/"
3a14 (BRE 轉譯) 3.14159 (BRE 不轉譯) 3a14 (ERE 轉譯) 3.14159 (ERE 不轉譯)
!
@
#
%
&
,
-
"
=
」:specChar='!'
specChar='@'
specChar='#'
specChar='%'
specChar='&'
specChar='_'
specChar=','
specChar='-'
specChar='"'
specChar='='
3.14159 (BRE 轉譯)
3.14159 (BRE 不轉譯)
3.14159 (ERE 轉譯)
3.14159 (ERE 不轉譯)
.
$
*
^
/
\
[
]
」:specChar='.'
3.14159 (BRE 轉譯)
3.14159 (BRE 不轉譯)
3.14159 (ERE 轉譯)
3.14159 (ERE 不轉譯)
不轉譯也正確,但因為「.」為匹配字元,應納入「BRE ERE 一律要轉譯的字元」。
specChar='$'
3.14159 (BRE 轉譯)
3.14159 (BRE 不轉譯)
3.14159 (ERE 轉譯)
3$14 (ERE 不轉譯)
specChar='*'
3.14159
3*3.14159
3.14159
3*3.14159
specChar='^'
3.14159
3.14159
3.14159
3^14
specChar='/' (定界字元)
3.14159 (BRE 轉譯)
Error (BRE 不轉譯)
3.14159 (ERE 轉譯)
Error (ERE 不轉譯)
specChar='\'
3.14159
Error
3.14159
Error
specChar='['
3.14159
Error
3.14159
Error
specChar=']'
3.14159
3.14159
3.14159
3.14159
BRE ERE 不轉譯跟轉譯後結果相同,但為了配合「[」,將「]」納入「BRE ERE 一律要轉譯的字元」。
/
),將 sed 的定界字元改為 _
。specChar='/'
echo "3${specChar}14" | sed -e "s_3\\${specChar}14_3\.14159_" &&\
echo "3${specChar}14" | sed -e "s_3${specChar}14_3.14159_" &&\
echo "3${specChar}14" | sed -E "s_3\\${specChar}14/3_.14159_" &&\
echo "3${specChar}14" | sed -E "s_3${specChar}14_3.14159_"
3.14159 (BRE 轉譯)
3.14159 (BRE 不轉譯)
3/14 (ERE 轉譯)
3.14159 (ERE 不轉譯)
`
'
<
>
」:specChar='`'
3`14 (BRE 轉譯)
3.14159 (BRE 不轉譯)
3`14 (ERE 轉譯)
3.14159 (ERE 不轉譯)
specChar="'"
3'14
3.14159
3'14
3.14159
specChar='<'
3<14
3.14159
3<14
3.14159
specChar='>'
3>14
3.14159
3>14
3.14159
+
?
|
(
)
{
}
」:specChar='+'
3+14 (BRE 轉譯)
3.14159 (BRE 不轉譯)
3.14159 (ERE 轉譯)
3+14 (ERE 不轉譯)
specChar='?'
3?3.14159
3.14159
3.14159
3?3.14159
specChar='|'
3.14159|14
3.14159
3.14159
3.14159|14
specChar='('
Error
3.14159
3.14159
Error
specChar=')'
Error
3.14159
3.14159
Error
specChar='{'
Error
3.14159
3.14159
Error
specChar='}'
3.14159
3.14159
3.14159
3.14159
BRE ERE 不轉譯跟轉譯後結果相同,但為了配合「{」,將「}」納入「BRE 不轉譯 ERE 要轉譯的字元」。