baicai

白菜

一个勤奋的代码搬运工!

使用 sed 命令進行複製、剪切和粘貼

很少有 Unix 命令像 sed、grep 和 awk 一樣出名,它們經常組合在一起,可能是因為它們具有奇怪的名稱和強大的文字解析能力。它們還在一些語法和邏輯上有相似之處。雖然它們都能用於文字解析,但都有其特殊性。本文研究 sed 命令,它是一個 流編輯器。

安裝 sed#

如果你使用的是 Linux、BSD 或 macOS,那麼它們已經安裝了 GNU 的或 BSD 的 sed。這些是原始 sed 命令的獨特重新實現。雖然它們很相似,但也有一些細微的差別。本文已經在 Linux 和 NetBSD 版本上進行了測試,所以你可以使用你的電腦上找到的任何 sed,但是對於 BSD sed,你必須使用短選項(例如 -n 而不是 --quiet)。

GNU sed 通常被認為是功能最豐富的 sed,因此無論你是否運行 Linux,你可能都想要嘗試一下。如果在 Ports 樹中找不到 GNU sed(在非 Linux 系統上通常稱為 gsed),你可以從 GNU 網站 下載源代碼。 安裝 GNU sed 的好處是,你可以使用它的額外功能,但是如果需要可移植性,還可以限制它以遵守 sed 的 POSIX 規範。

MacOS 用戶可以在 MacPorts 或 Homebrew 上找到 GNU sed。

在 Windows 上,你可以通過 Chocolatey 來 安裝 GNU sed。

了解模式空間和保留空間#

sed 一次只能處理一行。因為它沒有可視化模式,所以會創建一個 模式空間,這是一個內存空間,其中包含來自輸入流的當前行(刪除了尾部的任何換行符)。填充模式空間後,sed 將執行你的指令。當命令執行完時,sed 將模式空間中的內容打印到輸出流,默認是 標準輸出,但是可以將輸出重定向到文件,甚至使用 --in-place=.bak 選項重定向到同一文件。

然後,迴圈從下一個輸入行再次開始。

為了在遍歷文件時提供一點靈活性,sed 還提供了保留空間(有時也稱為 保留緩衝區),即 sed 內存中為臨時數據存儲保留的空間。你可以將保留空間當作剪貼板,實際上,這正是本文所演示的內容:如何使用 sed 複製 / 剪切和貼上。

首先,創建一個示例文本文件,其內容如下:

Line one
Line three
Line two

複製數據到保留空間#

要將內容放置在 sed 的保留空間,使用 hH 命令。小寫的 h 告訴 sed 覆蓋保留空間中的當前內容,而大寫的 H 告訴 sed 將數據追加到保留空間中已經存在的內容之後。

單獨使用,什麼都看不到:

$ sed --quiet -e '/three/ h' example.txt
$

--quiet(縮寫為 -n)選項禁止顯示所有輸出,但 sed 執行了我的搜索需求。在這種情況下,sed 選擇包含字串 three 的任何行,並將其複製到保留空間。我沒有告訴 sed 印出任何東西,所以沒有輸出。

從保留空間複製數據#

要了解保留空間,你可以從保留空間複製內容,然後使用 g 命令將其放入模式空間,觀察會發生什麼:

$ sed -n -e '/three/h' -e 'g;p' example.txt

Line three
Line three

第一個空白行是因為當 sed 第一次複製內容到模式空間時,保留空間為空。

接下來的兩行包含 Line three 是因為這是從第二行開始的保留空間。

該命令使用兩個唯一的腳本(-e)純粹是為了幫助提高可讀性和組織性。將步驟劃分為單獨的腳本可能會很有用,但是從技術上講,以下命令與一個腳本語句一樣有效:

$ sed -n -e '/three/h ; g ; p' example.txt

Line three
Line three

將數據追加到模式空間#

G 命令會將一個換行符和保留空間的內容添加到模式空間。

$ sed -n -e '/three/h' -e 'G;p' example.txt
Line one

Line three
Line three
Line two
Line three

此輸出的前兩行同時包含模式空間(Line one)的內容和空的保留空間。接下來的兩行與搜索文字(three)匹配,因此它既包含模式空間又包含保留空間。第三行的保留空間沒有變化,因此在模式空間(Line two)的末尾是保留空間(仍然是 Line three)。

用 sed 剪切和貼上#

現在你知道了如何將字串從模式空間轉到保留空間並再次返回,你可以設計一個 sed 腳本來複製、刪除,然後在文件中貼上一行。例如,將示例文件的 Line three 挪至第三行,sed 可以解決這個問題:

$ sed -n -e '/three/ h' -e '/three/ d' \
-e '/two/ G;p' example.txt
Line one
Line two
Line three
  • 第一個腳本找到包含字串 three 的行,並將其從模式空間複製到保留空間,替換當前保留空間中的任何內容。
  • 第二個腳本刪除包含字串 three 的任何行。這樣就完成了與文字處理器或文本編輯器中的 剪切 動作等效的功能。
  • 最後一個腳本找到包含字串 two 的行,並將保留空間的內容_追加_到模式空間,然後打印模式空間。

任務完成。

使用 sed 編寫腳本#

再說一次,使用單獨的腳本語句純粹是為了視覺和心理上的簡單。剪切和貼上命令作為一個腳本同樣有效:

$ sed -n -e '/three/ h ; /three/ d ; /two/ G ; p' example.txt
Line one
Line two
Line three

它甚至可以寫在一個專門的腳本文件中:

#!/usr/bin/sed -nf

/three/h
/three/d
/two/ G
p

要運行該腳本,將其加入可執行權限,然後用示例文件嘗試:

$ chmod +x myscript.sed
$ ./myscript.sed example.txt
Line one
Line two
Line three

當然,你需要解析的文本越可預測,則使用 sed 解決問題越容易。發明 sed 操作(例如複製和貼上)的 “配方” 通常是不切實際的,因為觸發操作的條件可能因文件而異。但是,你對 sed 命令的使用越熟練,就越容易根據需要解析的輸入來設計複雜的動作。

重要的事情是識別不同的操作,了解 sed 何時移至下一行,並預測模式和保留空間包含的內容。

sed 很複雜。雖然它只有十幾個命令,但它靈活的語法和原生功能意味著它充滿了無限的潛力。

參考#

How to use the Linux sed command [1]

使用 sed 命令進行複製、剪切和貼上 [2]

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。