我有一个通过参数调用的shell脚本(它由外部二进制程序调用,我无法更改),如下所示:
myscript.sh "param1" "param2"
现在,在这个脚本中有一个类似sed "s/param1/param2/"
的命令,param2
可以包含新行转义序列\n
(如line1\nline2
):
VAL=$(echo "$2" | sed -e 's/[\/&]/\\&/g')
sed -i "s/$1/$VAL/" /a/path/to/file
我已经这样做了:Escape a string for a sed replace pattern以逃避可能发生的反斜杠和&符号,但这无助于处理换行符\n
(sed
忽略它)。
我知道如何在脚本中手动完成(通过输入一个真实的换行符,在相应位置的shell脚本文件中按Return键或执行$(echo)
之类的操作),但我没有影响力传递的参数。
如何安全地处理换行序列以便sed完成其工作并在参数中出现\n
时插入换行符?
答案 0 :(得分:0)
在这种情况下,我强烈建议将sed
替换为perl
。如果您能够这样做,那么您的脚本将变为:
perl -pi -e 'BEGIN {$a=shift;$b=shift} s/$a/$b/' "$1" "$2" /a/path/to/file
您根本不再需要VAL
变量!
如果由于某些奇怪的原因您完全被限制为sed
,请将VAL=
声明更改为:
VAL=$(echo "$2" | sed -ne '1h;2,$H;$x;$s/[\/&]/\\&/g;$s/\n/\\n/g;$p;')
但不要这样做。请改用perl
版本。
答案 1 :(得分:0)
将\n
替换为真实换行符:
VAL=${VAL//\\n/$'\n'}
答案 2 :(得分:0)
来自BashFAQ #21,一个通用的字符串替换工具,使用awk
处理任意文字(新行和正则字符都不特殊):
# usage: gsub_literal STR REP
# replaces all instances of STR with REP. reads from stdin and writes to stdout.
gsub_literal() {
# STR cannot be empty
[[ $1 ]] || return
# string manip needed to escape '\'s, so awk doesn't expand '\n' and such
awk -v str="${1//\\/\\\\}" -v rep="${2//\\/\\\\}" '
# get the length of the search string
BEGIN {
len = length(str);
}
{
# empty the output string
out = "";
# continue looping while the search string is in the line
while (i = index($0, str)) {
# append everything up to the search string, and the replacement string
out = out substr($0, 1, i-1) rep;
# remove everything up to and including the first instance of the
# search string from the line
$0 = substr($0, i + len);
}
# append whatever is left
out = out $0;
print out;
}
'
}
当然,这是一个满口的,但使用起来很简单:
gsub_literal "$1" "$val" <infile >outfile
答案 3 :(得分:0)
VAL=$(echo "$2" | sed -e 's/[\/&]/\\&/g')
如何安全地处理换行序列,以便sed完成其工作并插入换行符 在
时\n
出现在参数?
您可以sed
添加\n
,s/\\n/\n/g
撤消 VAL=$(echo "$2" | sed -e 's/[\/&]/\\&/g;s/\\n/\n/g')
的转义。即
# set a 'line1\nline2'
# VAL=$(echo "$2" | sed -e 's/[\/&]/\\&/g;s/\\n/\n/g')
# sed "s/$1/$VAL/" <<<qay
qline1
line2y
测试:
{{1}}