Shell

如何使用 sed -i(就地編輯)實現可移植性?

  • April 3, 2019

我正在為我的伺服器編寫 shell 腳本,這是一個執行 FreeBSD 的共享主機。我還希望能夠在執行 Linux 的 PC 上本地測試它們。因此,我試圖以可移植的方式編寫它們,但sed我認為沒有辦法做到這一點。

我的網站的一部分使用生成的靜態 HTML 文件,並且此 sed 行在每次重新生成後插入正確的 DOCTYPE:

sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}

它適用sed於 Linux 上的 GNU,但 FreeBSDsed期望-i選項後的第一個參數是備份副本的擴展。這就是它的樣子:

sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}

然而,GNUsed反過來又期望表達式緊跟在-i. (它還需要使用換行符處理進行修復,但這已經在這裡回答了)

當然,我可以在腳本的伺服器副本中包含此更改,但這會弄亂即我使用 VCS 進行版本控制。有沒有辦法通過 sed 以完全可移植的方式實現這一目標?

GNU sed 在-i. 副檔名必須在同一個參數中,中間沒有空格。此語法也適用於 BSD sed。

sed -i.bak -e '…' SOMEFILE

請注意,在 BSD 上,-i當有多個輸入文件時也會改變行為:它們是獨立處理的(例如$匹配每個文件的最後一行)。這也不適用於 BusyBox。

如果您不想使用備份文件,可以檢查可用的 sed 版本。

case $(sed --help 2>&1) in
 *GNU*) set sed -i;;
 *) set sed -i '';;
esac
"$@" -e '…' "$file"

或者,為了避免破壞位置參數,定義一個函式。

case $(sed --help 2>&1) in
 *GNU*) sed_i () { sed -i "$@"; };;
 *) sed_i () { sed -i '' "$@"; };;
esac
sed_i -e '…' "$file"

如果您不想打擾,請使用 Perl。

perl -i -pe '…' "$file"

如果你想寫一個可移植的腳本,不要使用-i——它不在 POSIX 中。手動執行 sed 在後台所做的工作——它只是多了一行程式碼。

sed -e '…' "$file" >"$file.new"
mv -- "$file.new" "$file"

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