tl;博士:
使用BSD Sed(例如在macOS上也可以找到) ,您必须使用-i ''
而不是仅仅-i
(为了不创建备份文件)来使您的命令工作;例如:
sed -i '' 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='"$RABBITMQ_HOST"'/' "$Deploy_path"
要使您的命令同时适用于GNU和 BSD Sed,请指定一个非空选项参数(创建备份)并将其直接附加到-i
:
sed -i'.bak' 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='"$RABBITMQ_HOST"'/' "$Deploy_path" &&
rm "$Deploy_path.bak" # remove unneeded backup copy
背景信息、(更多)便携式解决方案和您的命令的改进可以在下面找到。
可选背景信息
听起来您正在使用BSD/macOS sed
,其-i
选项需要一个选项参数,该参数指定要创建的备份文件的后缀。
因此,您的sed
脚本(与您的期望相反)被解释为-i
'选项参数(备份后缀),而您的输入文件名被解释为script,这显然失败了。
相比之下,您的命令使用GNU sed
语法,-i
可以单独使用 where 来指示不保留要就地更新的输入文件的备份文件。
等效的BSD sed
选项是-i ''
- 注意技术需要使用单独的参数来指定 option-argument ''
,因为它是空字符串(如果使用-i''
,shell 会简单地剥离''
之前sed
看到的它:-i''
实际上与刚才相同-i
)。
遗憾的是,这不适用于GNU sed
,因为它仅在直接附加到时识别选项参数-i
,并将单独的参数解释''
为单独的参数,即脚本。
这种行为差异源于-i
选项实现背后的根本不同的设计决策,并且由于向后兼容性的原因,它可能不会消失。[1]
如果您不想创建备份文件,那么没有一种-i
语法适用于BSD和 GNU sed
。
有四个基本选项:
(a) 如果您知道您只会使用GNU或BSD,请相应地sed
构建-i
选项:-i
for GNU sed
,-i ''
for BSD sed
。
(b) 指定一个非空后缀作为-i
's option-argument,如果您将其直接附加到-i
选项,则适用于两种实现;例如,-i'.bak'
。虽然这总是会创建一个带有 suffix 的备份文件.bak
,但您可以在之后将其删除。
(c) 在运行时确定sed
您正在处理的实现并-i
相应地构造选项。
(d)-i
完全省略(不符合 POSIX 标准),并使用临时文件替换成功时的原始文件:sed '...' "$Deploy_path" > tmp.out && mv tmp.out "$Deploy_path"
.
请注意,这实际上是在-i
幕后所做的,它可能会产生意想不到的副作用,特别是作为符号链接的输入文件被替换为常规文件;,但是,确实保留了原始文件的某些属性:请参阅我的这个答案-i
的下半部分。
这是bash
(c) 的一个实现,它还简化了原始代码(sed
使用 2 次替换的单次调用)并使其更加健壮(变量被双引号括起来):
#!/bin/bash
RABBITMQ_HOST='rabbitmq1'
RABBITMQ_PASS='12345'
Deploy_path="test.env"
# Construct the Sed-implementation-specific -i option-argument.
# Caveat: The assumption is that if the `sed` is not GNU Sed, it is BSD Sed,
# but there are Sed implementations that don't support -i at all,
# because, as Steven Penny points out, -i is not part of POSIX.
suffixArg=()
sed --version 2>/dev/null | grep -q GNU || suffixArg=( '' )
sed -i "${suffixArg[@]}" '
s/^\(RABBITMQ_HOST\)=.*/\1='"$RABBITMQ_HOST"'/
s/^\(RABBITMQ_PASS\)=.*/\1='"$RABBITMQ_PASS"'/
' "$Deploy_path"
请注意,使用上面为$RABBITMQ_HOST
和定义的特定值$RABBITMQ_PASS
,将它们直接拼接到sed
脚本中是安全的,但如果值包含、 、 或换行符的实例&
,则需要预先转义以免破坏命令。
有关如何执行通用预转义的信息,请参阅我的这个答案,但此时您也可以考虑使用其他工具,例如and 。/
\
sed
awk
perl
[1] GNU Sed 将 option-argument 视为 -i optional,而 BSD Sed 则认为它是optional ,这也反映在语法规范中。在相应的man
页面中: GNU Sed: -i[SUFFIX]
vs. BSD Sed -i extension
。