use*_*364 3 bash awk sed inplace-editing ex
这是我的test.env
RABBITMQ_HOST=127.0.0.1
RABBITMQ_PASS=1234
Run Code Online (Sandbox Code Playgroud)
我想用它test.sh 来替换 to 中的值test.env:
RABBITMQ_HOST=rabbitmq1
RABBITMQ_PASS=12345
Run Code Online (Sandbox Code Playgroud)
这是我的test.sh
#!/bin/bash
echo "hello world"
RABBITMQ_HOST=rabbitmq1
RABBITMQ_PASS=12345
Deploy_path="./config/test.env"
sed -i 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='$RABBITMQ_HOST'/' $Deploy_path
sed -i 's/RABBITMQ_PASS=.*/RABBITMQ_PASS='$RABBITMQ_HOST'/' $Deploy_path
Run Code Online (Sandbox Code Playgroud)
但我有错误
sed: 1: "./config/test.env": invalid command code .
sed: 1: "./config/test.env": invalid command code .
Run Code Online (Sandbox Code Playgroud)
我该如何修复它?
长话短说:博士:
使用BSD Sed,例如macOS上的 Sed ,您必须使用-i ''而不是仅仅-i(为了不创建备份文件)来使您的命令起作用;例如:
sed -i '' 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='"$RABBITMQ_HOST"'/' "$Deploy_path"
Run Code Online (Sandbox Code Playgroud)
要使您的命令同时适用于GNU 和 BSD Sed,请指定一个非空选项参数(创建备份)并将其直接附加到-i:
sed -i'.bak' 's/RABBITMQ_HOST=.*/RABBITMQ_HOST='"$RABBITMQ_HOST"'/' "$Deploy_path" &&
rm "$Deploy_path.bak" # remove unneeded backup copy
Run Code Online (Sandbox Code Playgroud)
背景信息、(更多)便携式解决方案以及命令的改进可以在下面找到。
听起来您正在使用BSD/macOS sed,其-i选项需要一个选项参数来指定要创建的备份文件的后缀。
因此,您的sed 脚本(与您的预期相反)被解释为 的-i选项参数(备份后缀),并且您的输入文件名被解释为script,这显然会失败。
相比之下,您的命令使用GNU sed语法,其中-i可以单独使用来指示不保留要就地更新的输入文件的备份文件。
等效的BSD sed选项是-i ''- 请注意,技术上需要使用单独的参数来指定 option-argument '',因为它是空字符串(如果您使用-i'',shell 会简单地删除''之前sed看到的内容:-i''实际上与-i)。
遗憾的是,这不适用于GNU ,因为它仅在 直接附加到sed时识别选项参数,并将分离解释为单独的参数,即脚本。-i''
这种行为差异源于选项实现背后根本不同的设计决策-i,并且由于向后兼容性的原因,它可能不会消失。[1]
如果您不想创建备份文件,则没有-i适用于BSD和 GNU 的单一语法sed。
有四个基本选项:
(a) 如果您知道您只会使用GNU或BSDsed,请-i相应地构造选项:-ifor GNU sed,for -i ''BSD sed。
(b) 指定一个非空后缀作为-i的选项参数,如果将其直接附加到-i选项,则该后缀适用于两种实现;例如,-i'.bak'。虽然这总是会创建一个后缀为 的备份文件.bak,但您可以在之后将其删除。
(c) 在运行时确定sed您正在处理哪个实现并-i相应地构造选项。
(d) 完全省略-i(不符合 POSIX 标准),并使用临时文件在成功时替换原始文件:sed '...' "$Deploy_path" > tmp.out && mv tmp.out "$Deploy_path".
请注意,这本质上是在-i幕后所做的事情,这可能会产生意想不到的副作用,特别是作为符号链接的输入文件被常规文件替换;,但是,确实保留了原始文件的某些属性:请参阅我的这个答案-i的下半部分。
下面是bash(c) 的实现,它还简化了原始代码(一次sed调用,两次替换)并使其更加健壮(变量用双引号引起来):
#!/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"
Run Code Online (Sandbox Code Playgroud)
请注意,使用上面为$RABBITMQ_HOST和定义的特定值$RABBITMQ_PASS,可以安全地将它们直接拼接到sed脚本中,但如果这些值包含&、/、\或换行符的实例,则需要事先转义以免破坏命令sed。
请参阅我的这个答案,了解如何执行通用预转义,但此时您也可以考虑其他工具,例如awk和perl。
[1] GNU Sed 认为 -i 的选项参数是可选的,而 BSD Sed 认为它是强制的,这也反映在语法规范中。在相应的man页面中:GNU Sed:-i[SUFFIX]与 BSD Sed -i extension。
| 归档时间: |
|
| 查看次数: |
1101 次 |
| 最近记录: |