Red*_*Red 51 shell freebsd sed gnu portability
我正在为我的服务器编写 shell 脚本,这是一个运行 FreeBSD 的共享主机。我还希望能够在运行 Linux 的 PC 上本地测试它们。因此,我试图以可移植的方式编写它们,但sed我认为没有办法做到这一点。
我的网站的一部分使用生成的静态 HTML 文件,并且此 sed 行在每次重新生成后插入正确的 DOCTYPE:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Run Code Online (Sandbox Code Playgroud)
它适用sed于 Linux上的 GNU ,但 FreeBSDsed期望-i选项后的第一个参数是备份副本的扩展名。这是它的样子:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Run Code Online (Sandbox Code Playgroud)
但是,GNUsed反过来又希望表达式紧跟在 之后-i。(它还需要修复换行符处理,但这里已经回答了)
当然,我可以在脚本的服务器副本中包含此更改,但这会造成混乱,即我使用 VCS 进行版本控制。有没有办法以完全可移植的方式使用 sed 实现这一点?
Gil*_*il' 54
GNU sed 在-i. 扩展名必须在同一个参数中,中间没有空格。此语法也适用于 BSD sed。
sed -i.bak -e '…' SOMEFILE
Run Code Online (Sandbox Code Playgroud)
请注意,在 BSD 上,-i当有多个输入文件时也会改变行为:它们是独立处理的(例如$匹配每个文件的最后一行)。这也不适用于 BusyBox。
如果您不想使用备份文件,您可以检查可用的 sed 版本。
case $(sed --help 2>&1) in
*GNU*) set sed -i;;
*) set sed -i '';;
esac
"$@" -e '…' "$file"
Run Code Online (Sandbox Code Playgroud)
或者,为了避免破坏位置参数,定义一个函数。
case $(sed --help 2>&1) in
*GNU*) sed_i () { sed -i "$@"; };;
*) sed_i () { sed -i '' "$@"; };;
esac
sed_i -e '…' "$file"
Run Code Online (Sandbox Code Playgroud)
如果您不想打扰,请使用 Perl。
perl -i -pe '…' "$file"
Run Code Online (Sandbox Code Playgroud)
如果你想写一个可移植的脚本,不要使用-i——它不在 POSIX 中。手动执行 sed 在幕后所做的事情——它只是多一行代码。
sed -e '…' "$file" >"$file.new"
mv -- "$file.new" "$file"
Run Code Online (Sandbox Code Playgroud)
ter*_*don 13
如果你没有找到让sed游戏变得更好的技巧,你可以尝试:
不要使用-i:
sed '1s/^/<!DOCTYPE html> \n/' "${file_name.html}" > "${file_name.html}.tmp" &&
mv "${file_name.html}.tmp" "${file_name.html}"
Run Code Online (Sandbox Code Playgroud)使用 Perl
perl -i -pe 'print "<!DOCTYPE html> \n" if $.==1;' "${file_name.html}"
Run Code Online (Sandbox Code Playgroud)您始终可以使用ed在现有文件前添加一行。
$ printf '0a\n<!DOCTYPE html>\n.\nw\n' | ed my.html
Run Code Online (Sandbox Code Playgroud)
周围的位<!DOCTYPE html>是ed指示它将该行添加到文件的命令my.html。
我相信这个命令sed也可以使用:
$ sed -i '1i<!DOCTYPE html>\n` testfile.csv
Run Code Online (Sandbox Code Playgroud)
您还可以手动perl -i执行引擎盖下的操作:
{ rm -f file && { echo '<!DOCTYPE html>'; cat; } > file;} < file
Run Code Online (Sandbox Code Playgroud)
像perl -i,没有备份,并且像这里给出的大多数解决方案一样,请注意它可能会影响文件的权限、所有权,并且可能会将符号链接转换为常规文件。
和:
sed '1i\
<!DOCTYPE html>' file 1<> file
Run Code Online (Sandbox Code Playgroud)
sed会覆盖文件本身,因此不会影响所有权和权限或符号链接。它适用于 GNU,sed因为在用命令覆盖它之前,sed通常会从file(在我的情况下为 4k)读取一个充满数据的缓冲区i。如果文件超过 4k,那将不起作用,除了sed它还缓冲其输出的事实。
基本上sed适用于 4k 块进行读写。如果要插入的行小于 4k,sed则永远不会覆盖它尚未读取的块。
不过我不会指望它。