使用sed與否可見的臨時文件:

使用sed與否可見的臨時文件:

我的項目需要替換文件中的一些現有文本,例如foo與其他一些文字,如fooofoo:

abc.txt
name
foo
foo1

所以我嘗試:

sed -i "s/foo/fooofoo/g" abc.txt

但是我收到這個錯誤:

sed:非法選項--i

我在手冊中發現我必須使用:

sed -i\ "s/foo/fooofoo/g" abc.txt

然而這也不起作用。

我在perl和中找到了替代方案awk,但如果我能在 Solaris 中找到解決方案,我sed將不勝感激。

我正在使用這個版本的 bash:

GNU bash,版本 3.2.57(1)-release (sparc-sun-solaris2.10)

答案1

使用ed。它適用於大多數平台,並且可以就地編輯您的文件。
由於sed基於ed替換模式的語法類似:

ed -s infile <<\IN
,s/old/new/g
w
q
IN

答案2

如果無法安裝 GNU sed,請使用:

sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt

這使用重定向將 sed 的輸出傳送到臨時檔案。如果 sed 成功完成,則會覆蓋abc.txt臨時檔案。

從GNU sed的原始碼可以看出,這正是sed -i所做的。因此,這與sed -i.

如果有可能abc.tmp已經存在,那麼您可能需要使用mktemp或類似的實用程式來為臨時檔案產生唯一的名稱。

答案3

如果你想要 的等價物sed -i.bak,那就非常簡單。

考慮 GNU sed 的這個腳本:

#!/bin/sh

# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"

# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'

##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########

# Prove that it worked
ls "$dir"
cat "$dir/foo"

我們可以簡單地將標記線替換為

cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"

這會將現有檔案移至備份,並寫入新檔案。

如果我們想要相當於

sed -i -e "$script" "$dir"  # no backup

那就稍微複雜一些。我們可以打開檔案作為標準輸入讀取,然後取消連結它,然後指示 sed 的輸出替換它:

( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )

我們在子 shell 中執行此操作,以便我們的原始標準輸入在此之後仍然可用。可以在沒有子外殼的情況下切換輸入並切換回來,但這種方式對我來說似乎更清晰。

請注意,我們首先要小心複製,而不是創建一個新foo文件 - 如果該文件有多個名稱(即具有硬鏈接)並且您希望確保不會破壞鏈接,這一點很重要。

答案4

使用sed與否可見的臨時文件:

您可以避免創建單獨的可見的「臨時文件」:

exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-

解釋

類 Unix 系統實際上不會從磁碟中刪除檔案的內容,直到檔案被刪除為止。兩個都在檔案系統中取消鏈接,不在任何進程中開啟。因此,您可以exec 3<在 shell 中開啟檔案以讀取檔案描述符 3 rm(該檔案將其與檔案系統取消連結),然後sed使用檔案描述符 3 作為其輸入進行呼叫。

請注意,這是非常與此不同:

# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt

不同之處在於,當您在一個命令中執行此操作時,外殼程式只會打開同一個文件進行讀取和寫入,並且可以選擇截斷文件- 因為它仍然是同一個文件,所以您會丟失內容。但是,如果您打開它進行讀取,然後rm打開它,然後打開相同的路徑名進行寫入,您實際上是在相同的路徑名下創建一個新檔案(但在新的索引節點和磁碟位置,因為原始文件仍然打開):所以內容仍然可用。

然後,完成後,您可以關閉先前開啟的文件描述符(這就是exec 3<&-特殊語法的作用),這會釋放原始文件,以便作業系統可以刪除(標記為未使用)其磁碟空間。

注意事項

關於此解決方案,需要記住以下幾點:

  1. 您只能「瀏覽」一次內容 - 沒有便攜的shell 在檔案描述符中「尋找」的方式 - 因此一旦程式讀取了某些內容,其他程式將只能看到檔案的其餘部分。並將sed讀取整個文件。

  2. 如果您的 shell/script/sed 在完成之前被殺死,則原始檔案遺失的可能性很小。

相關內容