使用 sed 命令進(jìn)行復(fù)制、剪切和粘貼
了解 sed 的基本用法,然后下載我們的備忘單,方便快速地參考 Linux 流編輯器。
很少有 Unix 命令像 sed
、grep 和 awk 一樣出名,它們經(jīng)常組合在一起,可能是因?yàn)樗鼈兙哂衅婀值拿Q(chēng)和強(qiáng)大的文本解析能力。它們還在一些語(yǔ)法和邏輯上有相似之處。雖然它們都能用于文本解析,但都有其特殊性。本文研究 sed
命令,它是一個(gè) 流編輯器。
我之前寫(xiě)過(guò)關(guān)于 sed 以及它的遠(yuǎn)親 ed 的文章。要熟悉 sed
,對(duì) ed
有一點(diǎn)了解是有幫助的,因?yàn)檫@有助于你熟悉緩沖區(qū)的概念。本文假定你熟悉 sed
的基本知識(shí),這意味著你至少已經(jīng)運(yùn)行過(guò)經(jīng)典的 s/foo/bar
風(fēng)格的查找和替換命令。
- 下載我們的免費(fèi) sed 備忘錄
安裝 sed
如果你使用的是 Linux、BSD 或 macOS,那么它們已經(jīng)安裝了 GNU 的或 BSD 的 sed。這些是原始 sed
命令的獨(dú)特重新實(shí)現(xiàn)。雖然它們很相似,但也有一些細(xì)微的差別。本文已經(jīng)在 Linux 和 NetBSD 版本上進(jìn)行了測(cè)試,所以你可以使用你的計(jì)算機(jī)上找到的任何 sed,但是對(duì)于 BSD sed,你必須使用短選項(xiàng)(例如 -n
而不是 --quiet
)。
GNU sed 通常被認(rèn)為是功能最豐富的 sed,因此無(wú)論你是否運(yùn)行 Linux,你可能都想要嘗試一下。如果在 Ports 樹(shù)中找不到 GNU sed(在非 Linux 系統(tǒng)上通常稱(chēng)為 gsed),你可以從 GNU 網(wǎng)站 下載源代碼。 安裝 GNU sed 的好處是,你可以使用它的額外功能,但是如果需要可移植性,還可以限制它以遵守 sed 的 POSIX 規(guī)范。
MacOS 用戶(hù)可以在 MacPorts 或 Homebrew 上找到 GNU sed。
在 Windows 上,你可以通過(guò) Chocolatey 來(lái) 安裝 GNU sed。
了解模式空間和保留空間
sed 一次只能處理一行。因?yàn)樗鼪](méi)有可視化模式,所以會(huì)創(chuàng)建一個(gè) 模式空間,這是一個(gè)內(nèi)存空間,其中包含來(lái)自輸入流的當(dāng)前行(刪除了尾部的任何換行符)。填充模式空間后,sed 將執(zhí)行你的指令。當(dāng)命令執(zhí)行完時(shí),sed 將模式空間中的內(nèi)容打印到輸出流,默認(rèn)是 標(biāo)準(zhǔn)輸出,但是可以將輸出重定向到文件,甚至使用 --in-place=.bak
選項(xiàng)重定向到同一文件。
然后,循環(huán)從下一個(gè)輸入行再次開(kāi)始。
為了在遍歷文件時(shí)提供一點(diǎn)靈活性,sed 還提供了保留空間(有時(shí)也稱(chēng)為 保留緩沖區(qū)),即 sed 內(nèi)存中為臨時(shí)數(shù)據(jù)存儲(chǔ)保留的空間。你可以將保留空間當(dāng)作剪貼板,實(shí)際上,這正是本文所演示的內(nèi)容:如何使用 sed 復(fù)制/剪切和粘貼。
首先,創(chuàng)建一個(gè)示例文本文件,其內(nèi)容如下:
Line one
Line three
Line two
復(fù)制數(shù)據(jù)到保留空間
要將內(nèi)容放置在 sed 的保留空間,使用 h
或 H
命令。小寫(xiě)的 h
告訴 sed 覆蓋保留空間中的當(dāng)前內(nèi)容,而大寫(xiě)的 H
告訴 sed 將數(shù)據(jù)追加到保留空間中已經(jīng)存在的內(nèi)容之后。
單獨(dú)使用,什么都看不到:
$ sed --quiet -e '/three/ h' example.txt
$
--quiet
(縮寫(xiě)為 -n
)選項(xiàng)禁止顯示所有輸出,但 sed 執(zhí)行了我的搜索需求。在這種情況下,sed 選擇包含字符串 three
的任何行,并將其復(fù)制到保留空間。我沒(méi)有告訴 sed 打印任何東西,所以沒(méi)有輸出。
從保留空間復(fù)制數(shù)據(jù)
要了解保留空間,你可以從保留空間復(fù)制內(nèi)容,然后使用 g
命令將其放入模式空間,觀(guān)察會(huì)發(fā)生什么:
$ sed -n -e '/three/h' -e 'g;p' example.txt
Line three
Line three
第一個(gè)空白行是因?yàn)楫?dāng) sed 第一次復(fù)制內(nèi)容到模式空間時(shí),保留空間為空。
接下來(lái)的兩行包含 Line three
是因?yàn)檫@是從第二行開(kāi)始的保留空間。
該命令使用兩個(gè)唯一的腳本(-e
)純粹是為了幫助提高可讀性和組織性。將步驟劃分為單獨(dú)的腳本可能會(huì)很有用,但是從技術(shù)上講,以下命令與一個(gè)腳本語(yǔ)句一樣有效:
$ sed -n -e '/three/h ; g ; p' example.txt
Line three
Line three
將數(shù)據(jù)追加到模式空間
G
命令會(huì)將一個(gè)換行符和保留空間的內(nèi)容添加到模式空間。
$ sed -n -e '/three/h' -e 'G;p' example.txt
Line one
Line three
Line three
Line two
Line three
此輸出的前兩行同時(shí)包含模式空間(Line one
)的內(nèi)容和空的保留空間。接下來(lái)的兩行與搜索文本(three
)匹配,因此它既包含模式空間又包含保留空間。第三行的保留空間沒(méi)有變化,因此在模式空間(Line two
)的末尾是保留空間(仍然是 Line three
)。
用 sed 剪切和粘貼
現(xiàn)在你知道了如何將字符串從模式空間轉(zhuǎn)到保留空間并再次返回,你可以設(shè)計(jì)一個(gè) sed 腳本來(lái)復(fù)制、刪除,然后在文檔中粘貼一行。例如,將示例文件的 Line three
挪至第三行,sed 可以解決這個(gè)問(wèn)題:
$ sed -n -e '/three/ h' -e '/three/ d' \
-e '/two/ G;p' example.txt
Line one
Line two
Line three
- 第一個(gè)腳本找到包含字符串
three
的行,并將其從模式空間復(fù)制到保留空間,替換當(dāng)前保留空間中的任何內(nèi)容。 - 第二個(gè)腳本刪除包含字符串
three
的任何行。這樣就完成了與文字處理器或文本編輯器中的 剪切 動(dòng)作等效的功能。 - 最后一個(gè)腳本找到包含字符串
two
的行,并將保留空間的內(nèi)容_追加_到模式空間,然后打印模式空間。
任務(wù)完成。
使用 sed 編寫(xiě)腳本
再說(shuō)一次,使用單獨(dú)的腳本語(yǔ)句純粹是為了視覺(jué)和心理上的簡(jiǎn)單。剪切和粘貼命令作為一個(gè)腳本同樣有效:
$ sed -n -e '/three/ h ; /three/ d ; /two/ G ; p' example.txt
Line one
Line two
Line three
它甚至可以寫(xiě)在一個(gè)專(zhuān)門(mén)的腳本文件中:
#!/usr/bin/sed -nf
/three/h
/three/d
/two/ G
p
要運(yùn)行該腳本,將其加入可執(zhí)行權(quán)限,然后用示例文件嘗試:
$ chmod +x myscript.sed
$ ./myscript.sed example.txt
Line one
Line two
Line three
當(dāng)然,你需要解析的文本越可預(yù)測(cè),則使用 sed 解決問(wèn)題越容易。發(fā)明 sed 操作(例如復(fù)制和粘貼)的“配方”通常是不切實(shí)際的,因?yàn)橛|發(fā)操作的條件可能因文件而異。但是,你對(duì) sed 命令的使用越熟練,就越容易根據(jù)需要解析的輸入來(lái)設(shè)計(jì)復(fù)雜的動(dòng)作。
重要的事情是識(shí)別不同的操作,了解 sed 何時(shí)移至下一行,并預(yù)測(cè)模式和保留空間包含的內(nèi)容。
下載備忘單
sed 很復(fù)雜。雖然它只有十幾個(gè)命令,但它靈活的語(yǔ)法和原生功能意味著它充滿(mǎn)了無(wú)限的潛力。為了充分利用 sed,我曾經(jīng)參考過(guò)一些巧妙的單行命令,但是直到我開(kāi)始發(fā)明(有時(shí)是重新發(fā)明)自己的解決方案時(shí),我才覺(jué)得自己真正開(kāi)始學(xué)習(xí) sed 了 。如果你正在尋找命令提示和語(yǔ)法方面的有用技巧,下載我們的 sed 備忘單,然后開(kāi)始一勞永逸地學(xué)習(xí) sed!