目錄:
介紹工作原理正規表示式基本語法數字定址和正則定址基本子命令實戰練習
介紹
熟悉 Linux 的同學一定知道大名鼎鼎的 Linux 三劍客,它們是 grep
、awk
、sed
,我們今天要聊的主角就是 sed
。
sed 全名叫 stream editor
,流編輯器,用程式的方式來編輯文字,與 vim 的互動式編輯方式截然不同。它的功能十分強大,加上正規表示式的支援,可以進行大量的複雜文字的編輯操作。
實際上 sed 提供的功能非常複雜,有專門的書籍講解它。本文不會講 sed 的全部東西,只會從 sed 的工作原理、常見使用方法等方面進行說明和講解,同時也會給出大量的實踐用例來幫助更好的理解 sed 基本用法。文中的知識點真正掌握後,足以應付平時工作中的基本需求。
它有自己的使用場景:
- 自動化程式中,不適合互動方式編輯的;
- 大批量重複性的編輯需求;
- 編輯命令太過複雜,在互動文字編輯器難以輸入的情況;
工作原理
sed 作為一種非互動式編輯器,它使用預先設定好的編輯指令對輸入的文字進行編輯,完成之後輸出編輯結果。
簡單描述 sed 工作原理:
- sed 從輸入檔案中讀取內容,每次處理一行內容,並把當前的一行內容儲存在臨時的緩衝區中,稱為
模式空間
。 - 接著用 sed 命令處理快取區中的內容;
- 處理完畢後,把快取區的內容送往螢幕;
- 接著處理下一行;
這樣不斷重複,直到檔案末尾,檔案內容並沒有改變,除非你使用重定向輸出或指定了 i
引數
正規表示式
sed 基本上就是在玩正規表示式模式匹配,所以,會玩 sed 的人,正規表示式能力一般都比較強。正規表示式內容相對較多,本節不會重點講解正規表示式。
為了能夠讓大部分朋友比較輕鬆地學習本文知識,這裡還是簡單介紹下正規表示式的基本內容。如果是專門做正則程式設計開發的,可以去買本正則的書籍來看。
(一)基本正規表示式
.
,表示匹配任意一個字元,除了換行符,類似 Shell 萬用字元中的?
;*
,表示前邊字元有 0 個或多個;.*
,表示任意一個字元有 0 個或多個,也就是能匹配任意的字元;^
,表示行首,也就是每一行的開始位置,^abc
匹配以 abc 開頭的字串;$
,表示行尾,也就是每一行的結尾位置,}$
匹配以大括號結尾的字串;{}
,表示前邊字元的數量範圍,{2}
,表示重複 2 次,{2,}
重複至少 2次,{2,4}
重複 2-4 次;[]
,括號中可以包含表示字符集的表示式,使用方法大概如下幾種
(二)擴充套件正規表示式
擴充套件正規表示式使用頻率上沒有基本表示式那麼高,但依然很重要,很多情況下沒有擴充套件正則是搞不定的,sed 命令使用擴充套件正則時需要加上選項 -r
。
?
:表示前置字元有 0 個或 1 個;+
:表示前置字元有 1 個或多個;|
:表示匹配其中的一項即可;()
:表示分組,(a|b)b
表示可以匹配 ab 或 bb 子串,且命令表示式中可以通過\1
、\2
來表示匹配的變數{}
:和基本正則中的大括號中意義相同,只不過使用時不用加 轉義符號;
基本語法
先介紹下 sed 的基本語法。
sed [選項] 'command' filename
選項部分,常見選項包括:-n
、-e
、-i
、-f
、-r
等。
command 子命令格式:
[地址1, 地址2] [函式] [引數(標記)]
選項簡單說明:
-n
,表示安靜模式。預設 sed 會把每行內容處理完畢後列印到螢幕上,加上選項後就不會輸出到螢幕上。-e
,如果需要用 sed 對文字內容進行多種操作,則需要執行多條子命令來進行操作;-i
,預設 sed 只會處理模式空間的副本內容,不會直接修改檔案,如果需要修改檔案,就要指定-i
選項;-f
,如果命令操作比較多時,用-e
會有點力不從心,這時需要把多個子命令寫入指令碼檔案,使用-f
選項指定執行該指令碼;-r
:如果需要支援擴充套件正規表示式,那麼需要新增-r
選項;
數字定址和正則定址
預設情況下 sed 會對每一行內容進行匹配、處理、輸出,有時候我們不需要對所有內容進行操作,只需要修改一種一部分,比如 1-10 行,偶數行,或包括 hello 字串的行。
這種情況下,就需要我們去定位特定的行來進行處理,而不是全部內容,這裡把定位指定的行叫做 定址。
(一)數字定址
數字定址其實就是通過數字去指定要操作的行,有幾種方式,每種方式都有不同的應用場景。
# 只將第4行中hello替換為A
$ sed '4s/hello/A/g' file.txt
# 將第2-4行中hello替換為A
$ sed '2,4s/hello/A/g' file.txt
# 從第2行開始,往下數4行,也就是2-6行
$ sed '2,+4s/hello/A/g' file.txt
# 將最後1行中hello替換為A
$ sed '$s/hello/A/g' file.txt
# 除了第1行,其它行將hello替換為A
$ sed '1!s/hello/A/g' file.txt
(二)正則定址
正則定址,是通過正規表示式的匹配來確定需要處理編輯哪些行,其它行就不需要處理
# 將匹配到hello的行執行刪除操作,d 表示刪除
$ sed '/hello/d' file.txt
# 刪除空行,"^$" 表示空行
$ sed '/^$/d' file.txt
# 將匹配到以ts開頭的行到以te開頭的行之間所有行進行刪除
$ sed '/^ts/,/^te/d' file.txt
(三)數字定址和正則定址混用
數字定址和正則定址可以配合使用
# 匹配從第1行到ts開頭的行,把匹配的行執行刪除
$ sed '1,/^ts/d' file.txt
基本子命令
(一)替換子命令s
子命令 s
為替換子命令,是平時 sed 使用最多的命令,因為支援正規表示式,功能很強大,基本可以替代 grep
的基本用法。
基本語法:
[address]s/pat/rep/flags
替換子命令基本用法
# 將每行的hello替換為HELLO,只替換匹配到的第一個
$ sed 's/hello/HELLO/' file.txt
# 將匹配到的hello全部替換為HELLO,g表示替換一行所有匹配到的
$ sed 's/hello/HELLO/g' file.txt
# 將第2次匹配到的hello替換
$ sed 's/hello/A/2' file.txt
# 將第2次後匹配到的所有都替換
$ sed 's/hello/A/2g' file.txt
# 在行首加#號
$ sed 's/^/#/g' file.txt
# 在行尾加東西
$ sed 's/$/xxx/g' file.txt
正規表示式的簡單使用
# 使用擴充套件正規表示式,結果為:A
$ echo "hello 123 world" | sed -r 's/[a-z]+ [0-9]+ [a-z]+/A/'
# <b>This</b> is what <span style="x">I</span> meant
# 要求:去掉上述html檔案中的tags
$ sed 's/<[^>]*>//g' file.txt
多個匹配
# 將1-3行的my替換為your,且3行以後的This替換為That
$ sed '1,3s/my/your/g; 3,$s/This/That/g' my.txt
# 等價於
$ sed -e '1,3s/my/your/g' -e '3,$s/This/That/g' my.txt
使用匹配到的變數
# 將匹配到的字串前後加雙引號,結果為:My "name" chopin
# "&"表示匹配到的整個結果集
$ echo "My name chopin" | sed 's/name/"&"/'
# 如下命令,結果為:hello=world,"\1"和"\2"表示圓括號匹配到的值
$ echo "hello,123,world" | sed 's/\([^,]\),.*,\(.*\)/\1=\2/'
其它幾個常見用法
# 只將修改匹配到行內容列印出來,-n關閉了模式空間的列印模式
$ sed -n 's/i/A/p' file.txt
# 替換是忽略大小寫,將大小寫i替換為A
$ sed -n 's/i/A/i' file.txt
# 將替換後的內容另存為一個檔案
$ sed -n 's/i/A/w b.txt' file.txt
$ sed -n 's/i/A/' file.txt > b.txt
注意,sed 修改匹配到的內容後,預設行為是不儲存到原檔案,直接輸出修改後模式空間的內容,如果要修改原檔案需要指定 -i
選項。
(二)追加行子命令a
子命令 a
表示在指定行下邊插入指定的內容行;
# 將所有行下邊都新增一行內容A
$ sed 'a A' file.txt
# 將檔案中1-2行下邊都新增一行內容A
$ sed '1,2a A' file.txt
(三)插入行子命令i
子命令 i
和 a
使用基本一樣,只不過是在指定行上邊插入指定的內容行
# 將檔案中1-2行上邊都新增一行內容A
$ sed '1,2i A'
(四)替換行子命令c
子命令 c
是表示把指定的行內容替換為自己需要的行內容
# 將檔案所有行都分別替換為A
$ sed 'c A' file.txt
# 將檔案中1-2行內容替換為A,注意:兩行內容變成了一行A
$ sed '1,2c A' file.txt
# 將1-2行內容分別替換為A行內容
$ sed '1,2c A\nA' file.txt
(五)刪除行子命令d
子命令 d
表示刪除指定的內容行,這個很容理解
# 將檔案中1-3行內容刪除
$ sed '1,3d' file.txt
# 將檔案中This開頭的行內容刪除
$ sed '/^This/d' file.txt
(六)設定行號子命令=
子命令 =
,可以將行號列印出來
# 將指定行上邊顯示行號
$ sed '1,2=' file.txt
# 可以將行號設定在行首
$ sed '=' file.txt | sed 'N;s/\n/\t/'
(七)子命令N
子命令 N
,把下一行內容納入當快取區做匹配,注意的是第一行的 \n
仍然保留
其實就是當前行的下一行內容也讀進快取區,一起做匹配和修改,舉個例子吧
# 將偶數行內容合併到奇數行
$ sed 'N;s/\n//' file.txt
哈哈,是不是很簡單?
實戰練習
掌握了上邊的基礎命令操作後,基本上可以滿足平時 95%
的需求啦。sed 還有一些高階概念,比如:模式空間、保持空間、高階子命令、分支和測試等,平時使用概率非常小,本文就暫不講解了,有需要的同學可以私信我一起交流學習哈。
學習了這麼多基礎用法後,只要你勤加練習,多實踐,多使用,一定可以得心應手,極大提高的文字處理效率。下邊我簡單再給出一些比較實用的操作實踐,希望對大家有幫助。
1. 刪除檔案每行的第二個字元
$ sed -r 's/(.)(.)(.*)$/\1\3/' file.txt
2. 交換每行的第一個字元和第二個字元
$ sed -r ‘s/(.)(.)(.*)/\2\1\3/’ file.txt
3. 刪除檔案中所有的數字
$ sed 's/[0-9]//g' file.txt
4. 用製表符替換檔案中出現的所有空格
$ sed -r 's/ +/\t/g' file.txt
5. 把所有大寫字母用括號()括起來
$ sed -r 's/([A-Z])/(\1)/g'
6. 隔行刪除
$ sed '0~2{d}' file.txt
7. 刪除所有空白行
$ sed '/^$/d' file.txt
好了,以上是 sed 命令常用的全部內容。想要熟練掌握,只有多實踐,多練習正規表示式的使用,一旦熟練掌握後,相信在日後工作中一定會產生巨大作用的。
謝謝大家,我是肖邦,歡迎關注後續的精彩內容。
推薦閱讀: