如何使用自动脚本上的sed安全地处理“\ n”,其中“\ n”可以在这些脚本的输入中?

时间:2015-06-29 08:17:30

标签: bash shell sed

我有一个通过参数调用的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以逃避可能发生的反斜杠和&符号,但这无助于处理换行符\nsed忽略它)。

我知道如何在脚本中手动完成(通过输入一个真实的换行符,在相应位置的shell脚本文件中按Return键或执行$(echo)之类的操作),但我没有影响力传递的参数。

如何安全地处理换行序列以便sed完成其工作并在参数中出现\n时插入换行符?

4 个答案:

答案 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添加\ns/\\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}}