sed是一種流編輯器,能高效地完成各種替換、刪除、插入等操作,按照檔案資料行順序,重複處理滿足條件的每一行資料,然後把結果展示列印,且不會改變原檔案內容。
sed會逐行掃描輸入的資料,並將讀取的資料內容複製到臨時緩衝區中,稱為“模式空間”(pattern space),然後拿模式空間中的資料與給定的條件進行匹配,如果匹配成功,則執行特定的sed指令,否則跳過輸入的資料行,繼續讀取後面的資料。
一、命令介紹
1.1 命令語法
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
#如:
sed [選項] '匹配條件和操作指令' 檔名
cat 檔名 | sed [選項] '匹配條件和操作指令'
1.2 選項引數
-n, --quiet, --silent
#suppress automatic printing of pattern space
--debug #annotate program execution
-e script, --expression=script
#add the script to the commands to be executed
-f script-file, --file=script-file
#add the contents of script-file to the commands to be executed
--follow-symlinks
#follow symlinks when processing in place
-i[SUFFIX], --in-place[=SUFFIX]
#edit files in place (makes backup if SUFFIX supplied)
-l N, --line-length=N
#specify the desired line-wrap length for the 'l' command
--posix #disable all GNU extensions.
-E, -r, --regexp-extended
#use extended regular expressions in the script (for portability use POSIX -E).
-s, --separate
#consider files as separate rather than as a single, continuous long stream.
--sandbox
#operate in sandbox mode (disable e/r/w commands).
-u, --unbuffered
#load minimal amounts of data from the input files and flush the output buffers more often
-z, --null-data
#separate lines by NUL characters
--help #display this help and exit
--version #output version information and exit
選項 | 例子 |
---|---|
-n, --quiet, --silent 禁止自動列印模式(常配合'p'使用,僅顯示處理後的結果) |
sed -n '/hello/p' filename 使用 /hello/ 匹配含有 "hello" 的行,p 列印匹配的行 |
--debug 以註解的方式顯示 sed 的執行過程,幫助除錯指令碼 |
sed --debug 's/foo/bar/' filename 當你使用 sed 修改內容時,它會顯示除錯資訊,以便你瞭解指令碼是如何執行的 |
-e script, --expression=script 在命令列中直接指定 sed 指令碼(允許多個 sed 表示式) |
sed -e 's/foo/bar/' -e 's/hello/world/' filename 將檔案中的 foo 替換為 bar,然後將 hello 替換為 world |
-f script-file, --file=script-file 從指定的指令碼檔案中讀取 sed 命令 |
sed -f script.sed filename script.sed 是包含多個 sed 命令的指令碼檔案,sed 會按順序執行這些命令 |
--follow-symlinks 當指定 -i 時,sed 會跟隨符號連結(symlink)指向的實際檔案進行編輯 |
sed -i --follow-symlinks 's/foo/bar/' symlink.txt 如果 symlink.txt 是一個符號連結檔案,sed 會編輯它指向的實際檔案 |
-i[SUFFIX], --in-place[=SUFFIX] 直接編輯檔案(如果提供 SUFFIX,則進行備份) |
sed -i.bak 's/foo/bar/' filename 直接在 filename 中將 foo 替換為 bar,並建立一個備份檔案 filename.bak |
-l N, --line-length=N 當使用 l 命令(列出行內容)時,指定輸出的行寬(N 表示字元數) |
echo 'hello world' | sed -l 5 'l' 使用 l 命令顯示 "hello world",但每行最多顯示 5 個字元 |
--posix 禁用 GNU 擴充套件,使 sed 遵循 POSIX 標準語法 |
sed --posix 's/foo/bar/' filename 這將禁用 sed 的一些非標準特性,確保指令碼在 POSIX 環境下工作 |
-E, -r, --regexp-extended 使用擴充套件的正規表示式(ERE),這與基本正規表示式(BRE)相比,簡化了一些語法(例如不用轉義括號和 +) |
echo "abc123" | sed -E 's/[a-z]+([0-9]+)/\1/' 使用擴充套件正規表示式,匹配並提取字母后面的數字 |
-s, --separate 將多個輸入檔案視為獨立的流,而不是作為一個連續的流處理 |
sed -s 's/foo/bar/' file1.txt file2.txt sed 會分別處理 file1.txt 和 file2.txt,而不是將它們作為一個整體處理 |
--sandbox 以沙盒模式執行,禁止使用 e, r, w 命令,防止 sed 修改檔案或執行外部命令 |
sed --sandbox 's/foo/bar/' filename 啟用沙盒模式,防止 sed 指令碼執行危險的操作 |
-u, --unbuffered 減少從輸入檔案讀取資料時的緩衝區大小,並更頻繁地重新整理輸出 |
sed -u 's/foo/bar/' filename 立即將處理結果輸出到標準輸出,而不是等到處理大量資料後再輸出 |
-z, --null-data 將輸入中的行分隔符從換行符 \n 改為 NUL 字元 \0,這在處理二進位制資料或以 NUL 作為分隔符的文字時很有用 |
sed -z 's/foo/bar/' filename 使用 NUL 字元作為行分隔符處理文字 |
1.3 匹配條件
格式 | 描述 |
---|---|
/regexp/ | 使用 "正規表示式",匹配資料行 |
n(數字) | 使用 "行號" 匹配,範圍是 1-$ ($ 表示最後一行) |
addr1,addr2 | 使用 "行號或正則" 定位,匹配從 addr1 到 addr2 的所有行 |
addr1,+n | 使用 "行號或正則" 定位,匹配從 addr1 開始及後面的 n 行 |
n~step | 使用 "行號",匹配從行號 n 開始,步長為 step 的所有資料行 |
1.3.1 定界符
/ 在sed中作為定界符使用,也可以使用任意的定界符。
sed 's|foo|bar|g' filename
sed 's:foo:bar:g' filename
#定界符出現在樣式內部時,需要進行轉義:
sed 's/\/bin/\/usr\/bin/g' filename
1.3.2 變數引用
sed表示式使用單引號來引用,但是如果表示式內部包含"變數"字串,則需要使用雙引號。
foo="world"
echo "hello world" | sed "s/$foo/librarookie"
hello librarookie
1.4 操作指令
指令 | 描述 | 例子 |
---|---|---|
! <script> | 表示後面的命令,對 "所有沒有被選定" 的行發生作用 | sed -n '/foo/!p' filename 只列印不含有 "foo" 的行 |
p | 列印(print)當前匹配的資料行(常配合 -n 使用) | sed -n '/foo/p' filename 只列印含有 "foo" 的行 |
l | 小寫L,列印當前匹配的資料行,並顯示控制字元,如回車符\,結束符$等 | sed -n '/foo/l' filename 只列印含有 "foo" 的行,並顯示控制字元 |
= | 列印當前讀取的資料所在的 "行數" | sed -n '$=' filename 列印檔案最後一行的行數 |
a\ <text> | 在匹配的資料行 "後" 追加(append)文字內容 | sed '/foo/a\hello librarookie' filename 在每個含有 "foo" 行,下面追加一行 "hello librarookie" |
i\ <text> | 在匹配的資料行 "前" 插入(insert)文字內容 | sed '/foo/i\hello librarookie' filename 在每個含有 "foo" 行,上面插入一行 "hello librarookie" |
c\ <text> | 將匹配的資料行 "整行" 內容更改(change)為特定的文字內容 | sed '/foo/c\hello librarookie' filename 將每個含有 "foo" 整行,替換為 "hello librarookie" |
d | 行刪除,刪除(delete)匹配的資料行整行內容 | sed '/foo/d' filename 刪除每個含有 "foo" 的行 |
r <filename> | 從檔案中讀取(read)資料,並追加到匹配的資料行後面 | sed -i '/foo/r datafile' filename 將檔案 datafile 的內容,追加在檔案 filename 中每個含有 "foo" 的行下面 |
w <filename> | 將當前匹配到的資料,寫入(write)特定的檔案中 | sed -n '/foo/w newfile' filename 將檔案 filename 中每個含有 "foo" 的行,寫入到新檔案 newfile 裡面 |
q [exit code] | 立刻退出(quit)sed指令碼 | sed '5q' filename 列印第 5 行前的資料,類似 sed -n '1,5p |
s/regexp/replace/ | 使用正則匹配,將匹配的資料替換(substitute)為特定的內容 | sed 's/foo/bar/' filename 將每個含有 "foo" 行中,第一次出現的 "foo",替換為 "bar" |
n(數字) | 只替換第 n 次出現的匹配項 | sed 's/foo/bar/2' filename 將每個含有 "foo" 行中,第 2 次出現的 "foo",替換為 "bar" |
g | 全域性替換(Global substitution):替換每一行中的所有匹配項 | sed 's/foo/bar/g' filename 將每行中的 "foo" ,替換為 "bar" |
i | 忽略大小寫(Ignore case):進行不區分大小寫的匹配 | sed '/foo/i' filename 列印含有 "foo" 或 "FOO" 的行 |
e | 執行(Execute):允許在替換文字中進行命令執行 | echo "ls /tmp" | sed 's/ls/ls -l/e' 將sed命令的結果,當作命令執行;即輸出 ls -l /tmp 命令的結果 |
& | 引用匹配的整個字串 | echo "hello" | sed 's/hello/& librarookie/' 將每行中的 "foo" ,替換為 "bar" |
1.5 高階操作指令
指令 | 描述 |
---|---|
h | 將 "模式空間" 中的資料複製 到 "保留空間" |
H | 將 "模式空間" 中的資料追加 到 "保留空間" |
g | 將 "保留空間" 中的資料複製 到 "模式空間" |
G | 將 "保留空間" 中的資料追加 到 "模式空間" |
x | 將 "模式空間" 和 "保留空間" 中的資料交換 |
n | 讀取下一行資料複製 到 "模式空間" |
N | 讀取下一行資料追加 到 "模式空間" |
:label | 為 t 或 b 指令定義1abel標籤 |
t label | 有條件跳轉到標籤(1abel),如果沒有 1abel ,則跳轉到指令的結尾 |
b label | 跳轉到標籤(1abel),如果沒有 label ,則跳轉到指令的結尾 |
y/源/目標/ | 以字元為單位將源字元轉為為目標字元 |
二、常用例項
2.1 匹配範圍
#行號範圍:列印第3行到第5行
sed -n '3,5p' filename
#正規表示式匹配範圍:從匹配start_pattern的行開始,到匹配end_pattern的行結束
sed -n '/start_pattern/,/end_pattern/p' filename
#命令組合:從第1行開始,到第一個空白行為止
sed -n '1,/^$/p' filename
#倒數行範圍:從第1行開始,直到匹配end_pattern的行之前(使用!進行取反)
sed -n '1,/end_pattern/!p' filename
#指定行的倍數:列印所有奇數行(從第一行開始,步長為 2)
sed -n '1~2p' filename
2.2 增刪改
2.2.1 替換操作(s)
- 基礎替換
#只替換文字中第一次出現的匹配項,並將結果輸出到標準輸出
sed 's/foo/bar/' filename
#只替換每行中第三次出現的匹配項
sed 's/foo/bar/3' filename
#只列印替換過的行
sed -n 's/foo/bar/p' filename
#編輯原檔案,同時建立 filename.bak 備份
sed -i.bak 's/foo/bar/' filename
#忽略大小寫進行替換
sed 's/foo/bar/i' filename
#全域性替換
sed 's/foo/bar/g' filename
#全域性替換,每行替換從第 2 次開始出現的匹配項
sed 's/foo/bar/2g' filename
- 組合替換
#替換並寫入新檔案:將替換過的行寫入 output.txt
sed 's/foo/bar/w output.txt' filename
#結合標記符:在匹配的字串後新增字尾
sed 's/foo/&.bak/' filename
#執行sed結果的命令(謹慎使用,可能導致安全風險)
sed 's/systemctl start/systemctl status/e' filename
echo "ls /tmp" | sed 's/ls/ls -l/e'
#行號範圍:將第3行到第5行中的"foo"替換為"bar"
sed '3,5s/foo/bar/g' filename
#正規表示式匹配範圍:從包含"start"的行開始,到包含"end"的行結束,替換"foo"為"bar"
sed '/start/,/end/s/foo/bar/g' filename
#命令組合:從第1行開始,到第一個空白行為止,替換"foo"為"bar"
sed '1,/^$/s/foo/bar/g' filename
#倒數行範圍:從第1行開始,直到包含"end"的行之前,替換"foo"為"bar"
sed '1,/end/!s/foo/bar/g' filename
#指定行的倍數:替換所有奇數行中的"foo"為"bar"
sed '1~2s/foo/bar/g' filename
2.2.2 更新操作(a\i\c\)
a,i,c\ 分別表示在行下追加、行上插入和整行更新,字母符合後面
\
可以省略
2.2.2.1 行下追加(a\)
#將 "this is a test line" 追加到含有 "hello" 行的下面
sed -i '/hello/a\this is a test line' filename
#在第 2 行之後插入 "this is a test line"
sed -i '2a\this is a test line' filename
2.2.2.2 行上插入(i\)
#將 "this is a test line" 插入到含有 "librarookie" 的行上面
sed -i '/librarookie/i\this is a test line' filename
#在第 5 行之前插入 "this is a test line"
sed -i '5i\this is a test line' filename
2.2.2.3 替換當前行(c\)
#將含有 "librarookie" 的行變成 "this is a test line"
sed -i '/librarookie/c\this is a test line' filename
#將第 5 行變成 "this is a test line"
sed -i '3c\this is a test line' filename
2.2.3 刪除操作(d)
#刪除全文
sed -i 'd' filename
#刪除第 2 行
sed -i '2d' filename
#刪除最後一行
sed -i '$d' filename
#刪除空白行
sed -i '/^$/d' filename
#以 # 號開頭的行(刪除註釋)
sed -i '/^#/d' filename
#刪除檔案中所有開頭是 test的行
sed -i '/^test/d' filename
#刪除檔案的第 2 行到 末尾所有行
sed -i '2,$d' filename
2.3 指令碼檔案(-f)
sed指令碼 scriptfile 是一個sed的命令清單,啟動Sed時,以 -f 選項引導指令碼檔名。Sed指令碼規則如下:
1. 在命令的末尾不能有任何空白或文字;
2. 如果在一行中有多個命令,要用分號分隔;
3. 以 # 開頭的行為註釋行,且不能跨行;
#這將按照 scriptfile.sed 檔案中的命令來編輯 filename 檔案
sed -f scriptfile.sed filename
#如果你不希望實際修改檔案,可以新增 -n 標誌和 p命令來列印結果而不是直接寫入檔案
sed -nf scriptfile.sed filename
scriptfile.sed 內容如下:
# 這是註釋,會被sed忽略
# 替換檔案中的第一行中的"old_string"為"new_string"
1s/old_string/new_string/
# 從第3行到第5行,替換"foo"為"bar"
3,5s/foo/bar/g
# 刪除包含"delete_this_line"的行
/delete_this_line/d
# 在包含"insert_before"的行之前插入新行
/insert_before/i\
This is the new line to insert
# 在檔案末尾新增一行
$ a\
This is the new line at the end of the file
2.4 標記操作
2.4.1 已匹配字串標記(&)
符合匹配條件字串的標記,可以理解為匹配結果的變數名
#正規表示式 "\w\+" 匹配每一個單詞,使用 [&] 替換它,& 對應於之前所匹配到的單詞:
echo this is a test line | sed 's/\w\+/[&]/g'
[this] [is] [a] [test] [line]
# 將 hello 替換為 helloworld
sed 's/hello/&world/' filename
helloworld
2.4.2 子串匹配標記(\1)
匹配給定樣式的其中一部分:
1.\(..\)
用於匹配子串,對於匹配到的第一個子串就標記為\1
,依此類推匹配到的第二個結果就是\2
;
2. 未定義\(..\)
時,效果等同於&
標記;
#echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
this is 7 in a number
#命令中 digit 7,被替換成了 7。樣式匹配到的子串是 7。
#\(..\) 用於匹配子串。[a-z]+ 匹配小寫字母,為第一個子串\1;[A-Z]+ 匹配大寫字母,為第二個子串\2
echo "world HELLO" | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
HELLO world
# HELLO 被標記為 \1,將
echo "hello world" | sed 's/\(hello\) world/\1 librarookie/'
hello librarookie
2.5 組合多個表示式(-e)
#1. 使用 -e 選項,指定多個 sed 表示式
sed -e '表示式' -e '表示式' filename
#2. 使用管道符 | ,對結果重複使用 sed 命令
sed '表示式' | sed '表示式' filename
#1. 在表示式中使用 ;
sed '表示式; 表示式' filename
2.6 檔案讀寫(r/w)
#1. 從檔案讀取(r)
#將檔案 datafile 裡的內容讀取出來,顯示在檔案 filename 中匹配 test 的行下面
#如果匹配多行,則將檔案 datafile 的內容,顯示在檔案 filename 中所有匹配 test 的行下面
sed -i '/test/r datafile' filename
#2. 寫入新檔案(w)
#將檔案 filename 中所有匹配 test 的資料行,都寫入新檔案 newfile 裡面
sed -n '/test/w newfile' filename
#將替換後的 filename 寫入 newfile
sed 's/foo/bar/w newfile' filename
2.7 保留空間與模式空間
在 sed 編輯器中,有兩個非常重要的概念:保留空間(hold space)和模式空間(pattern space)。
-
模式空間(Pattern Space)
- 模式空間是 sed 用來處理輸入文字的地方。
- 當 sed 讀取輸入檔案的每一行時,它會將這一行放入模式空間,然後對模式空間中的內容執行指定的編輯命令。
- 預設情況下,模式空間的內容在處理後被輸出到標準輸出(通常是螢幕)。
- 模式空間的大小通常受限於系統記憶體,但通常足夠處理單行文字。
-
保留空間(Hold Space)
- 保留空間是 sed 的第二個緩衝區,它允許 sed 在處理模式空間的內容時儲存資料。
- 保留空間可以用來儲存模式空間中當前行的副本,或者用於在不同行之間傳遞資料。
2.7.1 保持和獲取(h/H/g/G)
#將任何包含 test 的行都被複制並追加到該檔案的末尾
sed -e '/test/h' -e '$G' file
# -e '/test/h'
#1. 匹配 test 的行被找到後,將存入模式空間,
#2. h 命令將其複製並存入保留空間(保持快取區的特殊緩衝區內)。
#
# -e '$G'
#1. 當到達最後一行($)後,
#2. G 命令取出保留空間的行,然後把它放回模式空間中,且追加到現在已經存在於模式空間中的行的末尾。
#3. 在這個例子中就是追加到最後一行。
2.7.2 保持和互換(h/x)
互換模式空間和保持緩衝區的內容。也就是把包含test與check的行互換:
sed -e '/test/h' -e '/check/x' file
2.8 列印奇數行或偶數行
#方法1:利用 n ,列印一行,隱藏一行
sed -n 'p;n' test.txt #奇數行
sed -n 'n;p' test.txt #偶數行
#方法2:利用步長 2 ,跳過非目標行
sed -n '1~2p' test.txt #奇數行
sed -n '2~2p' test.txt #偶數行
2.9 退出命令(q)
#列印完第10行後,退出sed
sed '10q' filename