Bash

替代不寫入臨時文件的 sed -i

  • August 30, 2021

我有幾個編輯模板文本文件的腳本,通過刪除“標籤”並將其替換為例如數字。為此,我使用

sed -i

命令。但是,我在執行腳本的伺服器上存在寫入/讀取時間問題,這使得腳本需要很長時間才能執行,因為 sed -i 命令會在每次執行時將臨時文件寫入磁碟。

有沒有我可以使用的替代方法,即不會為每次替換都將臨時文件寫入磁碟?是否可以在記憶體中編輯文本文件並且僅在執行所有替換後才寫入,或者我可以將多個替換堆疊到同一個 sed 命令中嗎?

為了澄清,該腳本具有以下形式:

input=shiftLeft.txt
while IFS= read -r line
do
   sed -i "s/install, element = $line, at=/install, element = $line, at= -0.001 +/g" processedFiles/layoutDB.seq
done < "$input"

也就是說,我從一個文本文件中讀取值,然後根據這些值在另一個文本文件中進行一些更改。對大量值重複執行此操作。

您的問題不在於sed -i創建了許多臨時文件,而是您使用相同的輸入文件多次執行它,並且每個都為輸出創建一個臨時文件,如下strace所示:

execve("/bin/sed", ["sed", "-i", "-e", "", "/tmp/foo"], 0x7fff10da5288 /* 36 vars */) = 0
openat(AT_FDCWD, "/tmp/foo", O_RDONLY)  = 3
openat(AT_FDCWD, "/tmp/sedVdjaBk", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("/tmp/sedVdjaBk", "/tmp/foo")    = 0
+++ exited with 0 +++

解決方案是只執行sed -i一次。

為此,首先編寫一個sed將輸入文件轉換為sed程序的命令。這看起來像:

sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!"

(如果輸入文件包含正則表達式有效字元,例如,我們可以改進這一點,s/install, element = &, at=/\& -0.001 +/g但這超出了這個問題的範圍)。

對此進行測試以確保您對生成的腳本感到滿意。

然後我們需要讓另一個sed使用轉換後的文本作為它的程序文件。我們可以通過告訴它從標準輸入讀取程序來做到這一點(儘管有替代方案¹):

sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!' \
   shiftLeft.txt |
sed -f - -i processedFiles/layoutDB.seq

再次,測試這個(不帶-i標誌),直到你滿意它做了你想要的。


¹ 由於我們使用的是bash,我們可以使用程序替換:

sed -f <(sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!' shiftLeft.txt) \
   -i processedFiles/layoutDB.seq

在標準 shell 中,我們需要將轉換後的文本擷取為字元串,並將其作為命令行腳本提供:

sed -e "$(sed -e 's!.*!s/install, element = &, at=/install, element = &, at= -0.001 +/g!' shiftLeft.txt)" \
   -i processedFiles/layoutDB.seq

引用自:https://unix.stackexchange.com/questions/666840