
我的項目需要替換文件中的一些現有文本,例如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<&-
特殊語法的作用),這會釋放原始文件,以便作業系統可以刪除(標記為未使用)其磁碟空間。
注意事項
關於此解決方案,需要記住以下幾點:
您只能「瀏覽」一次內容 - 沒有便攜的shell 在檔案描述符中「尋找」的方式 - 因此一旦程式讀取了某些內容,其他程式將只能看到檔案的其餘部分。並將
sed
讀取整個文件。如果您的 shell/script/sed 在完成之前被殺死,則原始檔案遺失的可能性很小。