我正在为我的服务器编写 shell 脚本,该服务器是运行 FreeBSD 的共享主机。我还希望能够在运行 Linux 的 PC 上本地测试它们。因此,我试图以可移植的方式编写它们,但sed
我认为没有办法做到这一点。
我的网站的一部分使用生成的静态 HTML 文件,并且此 sed 行在每次重新生成后插入正确的 DOCTYPE:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
它可以与 Linux 上的 GNU 配合使用sed
,但 FreeBSDsed
期望选项后的第一个参数-i
是备份副本的扩展名。它看起来是这样的:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
然而,GNUsed
反过来期望表达式紧跟在 后面-i
。 (它还需要修复换行处理,但这已经在这里)
当然,我可以在脚本的服务器副本中包含此更改,但这会弄乱我使用 VCS 进行版本控制的情况。有没有办法用 sed 以完全可移植的方式实现这一点?
答案1
GNU sed 接受-i
.扩展名必须位于同一参数中,中间不得有空格。此语法也适用于 FreeBSD sed。
sed -i.bak -e '…' SOMEFILE
请注意,在 FreeBSD 上,-i
当存在多个输入文件时,也会更改行为:它们是独立处理的(例如,$
匹配每个文件的最后一行)。而且这在 BusyBox 上不起作用。
如果您不想使用备份文件,您可以检查可用的 sed 版本。
# Assume that sed is either FreeBSD/macOS or GNU
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"
答案2
如果你找不到让sed
游戏变得更好的技巧,你可以尝试:
不要使用
-i
:sed '1s/^/<!DOCTYPE html> \n/' "${file_name.html}" > "${file_name.html}.tmp" && mv "${file_name.html}.tmp" "${file_name.html}"
使用 Perl
perl -i -pe 'print "<!DOCTYPE html> \n" if $.==1;' "${file_name.html}"
答案3
编辑
您始终可以使用ed
在现有文件前面添加一行。
$ printf '0a\n<!DOCTYPE html>\n.\nw\n' | ed my.html
细节
周围的位<!DOCTYPE html>
是指示ed
它将该行添加到文件的命令my.html
。
sed
我相信这个命令sed
也可以使用:
$ sed -i '1i<!DOCTYPE html>\n` testfile.csv
答案4
自由BSDsed也在 Mac OS X 上使用,需要切换-e
后的选项-i
来正确且明确地定义和识别以下(正则表达式)命令。
换句话说,sed -i -e ...
应该与 FreeBSD 和 GNU 一起使用sed
。
更一般地,在 FreeBSD 之后省略备份扩展sed -i
需要一些明确的sed
选项或开关,以避免在解析其命令行参数时-i
FreeBSD 部分出现混乱。sed
(但是请注意,就地sed
文件编辑会导致文件 inode 更改,请参阅“就地”编辑文件)。
(作为一般提示,最新版本的 FreeBSDsed
已-r
切换以增加与 GNU 的兼容性sed
)。
echo a > testfile.txt
ls -li testfile.txt
#gsed -i -e 's/a/A/' testfile.txt
#bsdsed -i 's/a/A/' testfile.txt # does not work
bsdsed -i -e 's/a/A/' testfile.txt
ls -li testfile.txt
cat testfile.txt