1. 程式人生 > >Linux常用命令之sed(2)

Linux常用命令之sed(2)

代碼 並不會 獨立 command 不存在 chan posix 通用 示例

Sed

  • SED的英文全稱是 Stream EDitor,它是一個簡單而強大的文本解析轉換工具,在1973-1974年期間由貝爾實驗室的Lee E. McMahon開發,今天,它已經運行在所有的主流操作系統上了。
  • McMahon創建了一個通用的行編輯器,最終變成為了SED。SED的很多語法和特性都借鑒了ed編輯器。設計之初,它就已經支持正則表達式,SED可以從文件中接受類似於管道的輸入,也可以接受來自標準輸入流的輸入。
  • SED由自由軟件基金組織(FSF)開發和維護並且隨著GNU/Linux進行分發,因此,通常它也稱作 GNU SED。對於新手來說,SED的語法看起來可能有些神秘,但是,一旦掌握了它的語法,你就可以只用幾行代碼去解決非常復雜的任務,這就是SED的魅力所在。

DESCRIPTION

工作流

  1. 讀取: SED從輸入流(文件,管道或者標準輸入)中讀取一行並且存儲到它叫做 模式空間(pattern buffer) 的內部緩沖區
  2. 執行: 默認情況下,所有的SED命令都在模式空間中順序的執行,除非指定了行的地址,否則SED命令將會在所有的行上依次執行
  3. 顯示: 發送修改後的內容到輸出流。在發送數據之後,模式空間將會被清空。
  4. 在文件所有的內容都被處理完成之前,上述過程將會重復執行

註意

  • 模式空間 (pattern buffer) 是一塊活躍的緩沖區,在sed編輯器執行命令時它會保存待檢查的文本
  • 默認情況下,所有的SED命令都是在模式空間中執行,因此輸入文件並不會發生改變
  • 還有另外一個緩沖區叫做 保持空間 (hold buffer),在處理模式空間中的某些行時,可以用保持空間來臨時保存一些行。在每一個循環結束的時候,SED將會移除模式空間中的內容,但是該緩沖區中的內容在所有的循環過程中是持久存儲的。SED命令無法直接在該緩沖區中執行,因此SED允許數據在 保持空間 和 模式空間之間切換
  • 初始情況下,保持空間 和 模式空間 這兩個緩沖區都是空的
  • 如果沒有提供輸入文件的話,SED將會從標準輸入接收請求
  • 如果沒有提供地址範圍的話,默認情況下SED將會對所有的行進行操作

語法

sed [-n] [-e] 'command(s)' files 
sed
[-n] -f scriptfile files
  • 第一種方式在命令行中使用單引號指定要執行的命令
  • 第二種方式則指定了包含SED命令的腳本文件。

當然,這兩種方法也可以同時使用,SED提供了很多參數用於控制這種行為。
讓我們看看如何指定多個SED命令。SED提供了delete命令用於刪除某些行,這裏讓我們刪除第一行,第二行和第五行:

$ cat books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

使用Sed移除指定的行,刪除三行,使用-e選項指定三個獨立的命令

# 3) The Alchemist, Paulo Coelho, 197 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 6) A Game of Thrones, George R. R. Martin, 864
sed -e '1d' -e '2d' -e '5d' books.txt

將多個SED命令寫在一個文本文件中,然後將該文件作為SED命令的參數,SED可以對模式空間中的內容執行文件中的每一個命令

echo -e "1d\n2d\n5d" > commands.txt 
# 1d
# 2d
# 5d
cat commands.txt
# 3) The Alchemist, Paulo Coelho, 197 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 6) A Game of Thrones, George R. R. Martin, 864
sed -f commands.txt books.txt

標準選項

-n

  • 默認情況下,模式空間中的內容在處理完成後將會打印到標準輸出,該選項用於阻止該行為

    # 1) A Storm of Swords, George R. R. Martin, 1216 
    # 2) The Two Towers, J. R. R. Tolkien, 352 
    # 3) The Alchemist, Paulo Coelho, 197 
    # 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
    # 5) The Pilgrimage, Paulo Coelho, 288 
    # 6) A Game of Thrones, George R. R. Martin, 864
    sed '' books.txt

    -e

  • 指定要執行的命令,使用該參數,我們可以指定多個命令

    # 1) A Storm of Swords, George R. R. Martin, 1216 
    # 2) The Two Towers, J. R. R. Tolkien, 352 
    # 3) The Alchemist, Paulo Coelho, 197 
    sed -n -e '1p' -e '2p' -e '3p' books.txt

-f

  • 指定包含要執行的命令的腳本文件

GNU選項

-n, –quiet, –slient

  • 與標準的-n選項相同

-e script,–expression=script

  • 與標準的-e選項相同

-f script-file, –file=script-file

  • 與標準的-f選項相同
  • 如果提供該選項的話,在編輯的文件是符號鏈接時,SED將會跟隨鏈接

    -i[SUFFIX],–in-place[=SUFFIX]

  • 該選項用於對當前文件進行編輯,如果提供了SUFFIX的話,將會備份原始文件,否則將會覆蓋原始文件

-l N, –line-lenght=N

  • 該選項用於設置行的長度為N個字符

–posix

  • 該選項禁用所有的GNU擴展

-r,–regexp-extended

  • 該選項將啟用擴展的正則表達式

-u, –unbuffered

  • 指定該選項的時候,SED將會從輸入文件中加載最少的數據,並且更加頻繁的刷出到輸出緩沖區。在編輯tail -f命令的輸出,你不希望等待輸出的時候該選項是非常有用的。

-z,–null-data

  • 默認情況下,SED對每一行使用換行符分割,如果提供了該選項的話,它將使用NULL字符分割行

模式空間和保持空間

模式空間

$ vim books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho,288 
6) A Game of Thrones, George R. R. Martin, 864

執行p命令

$ sed 'p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864 
6) A Game of Thrones, George R. R. Martin, 864

被顯示了兩次!

默認情況下,SED將會輸出模式空間中的內容,另外,我們的命令中包含了輸出命令p,因此每一行被打印兩次。但是不要擔心,SED提供了-n參數用於禁止自動輸出模式空間的每一行的行為

$ sed -n 'p' books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 
6) A Game of Thrones, George R. R. Martin, 864

行尋址

默認情況下,在SED中使用的命令會作用於文本數據的所有行。如果只想將命令作用於特定的行或者某些行,則需要使用 行尋址 功能。

  • 數字形式表示的行區間
  • 文本模式來過濾行
[address]command
數字方式的行尋址
# 3) The Alchemist, Paulo Coelho, 197 
sed -n '3p' books.txt
#2---5
sed -n '2,5 p' books.txt 
# 6) A Game of Thrones, George R. R. Martin, 864
sed -n '$ p' books.txt 
# 第三行到最後一行
sed -n '3,$ p' books.txt
# M, +n 將會打印出從第M行開始的下n行
sed -n '2,+4 p' books.txt
# M~N的形式,它告訴SED應該處理M行開始的每N行,50~5匹配行號50,55,60,65
# 奇數行
sed -n '1~2 p' books.txt 
# 偶數行
sed -n '2~2 p' books.txt 
文本模式過濾器
/pattern/command

必須用正斜線將要指定的pattern封起來。sed編輯器會將該命令作用到包含指定文本模式的行上。

# 3) The Alchemist, Paulo Coelho, 197 
# 5) The Pilgrimage, Paulo Coelho, 288 
sed -n '/Paulo/ p' books.txt

# 第一次匹配到Alchemist開始輸出,直到第5行為止。
# 3) The Alchemist, Paulo Coelho, 197 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
sed -n '/Alchemist/, 5 p' books.txt

# 使用逗號(,)操作符指定匹配多個匹配的模式。下列的示例將會輸出Two和Pilgrimage之間的所有行
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
sed -n '/Two/, /Pilgrimage/ p' books.txt

# 第一次Two出現的位置開始輸出接下來的4行
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed -n '/Two/, +4 p' books.txt 

保持空間

在處理模式空間中的某些行時,可以用保持空間來臨時保存一些行。有5條命令可用來操作保持空間

  • h 將模式空間復制到保持空間
  • H 將模式空間附加到保持空間
  • g 將保持空間復制到模式空間
  • G 將保持空間附加到模式空間
  • x 交換模式空間和保持空間的內容
# 1) A Storm of Swords, George R. R. Martin, 1216 , 2) The Two Towers, J. R. R. Tolkien, 352 
# - 3) The Alchemist, Paulo Coelho, 197 , 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# - 5) The Pilgrimage, Paulo Coelho, 288 , 6) A Game of Thrones, George R. R. Martin, 864
sed -n 'h;n;H;x;s/\n/, /;/Paulo/!b Print; s/^/- /; :Print;p' books.txt

刪除命令 d

[address1[,address2]]d

address1address2是開始和截止地址,它們可以是行號或者字符串匹配模式,這兩種地址都是可選的。

#
sed 'd' books.txt

# 移除第四行
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '4d' books.txt 

# 移除N1到N2行
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '2, 4 d' books.txt   

# 除所有作者為Paulo Coelho的書籍
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '/Paulo Coelho/d' books.txt 

# 移除所有以Storm和Fellowship開頭的行
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '/Storm/,/Fellowship/d' books.txt  

文件寫入命令 w

[address1[,address2]]w file

w指定是寫命令, file指的是存儲文件內容的文件名。使用file操作符的時候要小心,當提供了文件名但是文件不存在的時候它會自動創建,如果已經存在的話則會覆蓋原文件的內容。

# 創建文件books.txt的副本,在 w 和 file 之間只能有一個空格
sed -n 'w books.bak' books.txt
#
diff books.txt books.bak
# 會存儲文件中的偶數行到另一個文件
sed -n '2~2 w zing.txt' books.txt 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 6) A Game of Thrones, George R. R. Martin, 864
cat zing.txt 
# 存儲所有獨立作者的書到單獨的文件
sed -n -e '/Martin/ w Martin.txt' -e '/Paulo/ w Paulo.txt' -e '/Tolkien/ w Tolkien.txt' books.txt  
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 6) A Game of Thrones, George R. R. Martin, 864
cat Martin.txt
# 3) The Alchemist, Paulo Coelho, 197 
# 5) The Pilgrimage, Paulo Coelho, 288 
cat Paulo.txt
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
cat Tolkien.txt
追加命令 a
[address]a\ 
Append text
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 7) Adultry, Paulo Coelho, 234
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '4 a 7) Adultry, Paulo Coelho, 234' books.txt

# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
# 7) Adultry, Paulo Coelho, 234
sed '$ a 7) Adultry, Paulo Coelho, 234' books.txt

# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 7) Adultry, Paulo Coelho, 234
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '/The Alchemist/ a 7) Adultry, Paulo Coelho, 234' books.txt  
行替換命令 c

SED通過 c 提供了 change 和 replace 命令,該命令幫助我們使用新文本替換已經存在的行,當提供行的地址範圍時,所有的行都被作為一組被替換為單行文本,下面是該命令的語法

[address1[,address2]]c\ 
Replace text
# 替換文本中的第三行為新的內容
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) Adultry, Paulo Coelho, 324
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '3 c 3) Adultry, Paulo Coelho, 324' books.txt

# 接受模式作為地址
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) Adultry, Paulo Coelho, 324
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864
sed '/The Alchemist/ c 3) Adultry, Paulo Coelho, 324' books.txt

# 將第4-6行內容替換為單行
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 4) Adultry, Paulo Coelho, 324
sed '4, 6 c 4) Adultry, Paulo Coelho, 324' books.txt 
插入命令 i

插入命令與追加命令類似,唯一的區別是插入命令是在匹配的位置前插入新的一行。

[address]i\ 
Insert text
# 1) A Storm of Swords, George R. R. Martin, 1216 
# 2) The Two Towers, J. R. R. Tolkien, 352 
# 3) The Alchemist, Paulo Coelho, 197 
# 7) Adultry, Paulo Coelho, 324
# 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
# 5) The Pilgrimage, Paulo Coelho, 288 
# 6) A Game of Thrones, George R. R. Martin, 864

Linux常用命令之sed(2)