【问题标题】:Using SED to replace long string - but got unterminated substitute in regular expression使用 SED 替换长字符串 - 但在正则表达式中得到未终止的替换
【发布时间】:2019-02-01 02:19:43
【问题描述】:

hi 试图用一个长字符串替换下面的字符串:

@x@ 

使用我从命令行获得的字符串:

read test    
sed -i --backup 's/@x@/'${test}'/g' file.json README.md

但它仅适用于 1 个单词, 如果 word 之间有空格,则它不起作用。即使在引号之间

sed: 1: "s/@x@/string test string: unterminated substitute in regular expression

【问题讨论】:

  • 变量引用应始终用双引号括起来以避免此类问题。使用类似sed -i --backup 's/@x@/'"${test}"'/g' file.json README.md 或只是sed -i --backup "s/@x@/${test}/g" file.json README.md 的东西。 Shellcheck.net 擅长发现此类常见问题。
  • 此外,您应该添加一些健全性检查,以便嵌入变量不包含将被解释为 sed 命令一部分的字符。例如,${test//\//} 将使用参数扩展去除正斜杠。

标签: linux macos sed quoting


【解决方案1】:

问题源于您使用单引号的方式。目前,您正在 2. 单引号后面终止您的输入。查看错误消息,它让您意识到它缺少某些东西。

如果您的文件包含以下内容:

foo @x@ foo

您可以替换内容,例如使用以下命令:

sed 's/@x@/bar foo bar/' foo.txt > foo2.txt

得到:

foo bar foo bar foo

如果您需要传入变量,Gordon Davisson 的评论会告诉您正确的方法。

顺便说一句,如果你想使用 inplace 选项,在我的 linux 上你需要使用如下命令:

sed -i.old "s/@x@/${test}/" foo.txt

但我认为这可能取决于您的环境(mac?)。

【讨论】:

  • 但我不发送带引号的字符串。
  • 报价不是唯一的潜在问题,/s、&s、\<number>s 等等也是如此。一旦解决了引号问题,您仍然会遇到无法使用 sed 用任何字符串可靠地替换正则表达式的问题。请参阅 stackoverflow.com/q/29613304/1745001 了解预处理替换字符串所需的内容。
  • wrt The single-quotes ... needs to be escaped or removed. - 不,他们没有。您不能在单引号分隔的字符串/脚本中转义单引号,并且将脚本括在单引号中是正确的,但打开一个部分让 shell 解释它,例如扩展一个变量。 OP 引用错误只是没有双引号变量 - 's/@x@/'"${test}"'/g'。正如我在其他评论和回答中提到的,当然还有其他问题。此外,wrt UNIX 变体 - AFAIK mac 运行 BSD UNIX 变体,而不是 linux UNIX 变体。
【解决方案2】:

sed 不理解字符串是一系列文字字符的字符串。它将正则表达式(不是字符串)替换为启用反向引用的“字符串”(也不是字符串),所有这些都在一组定界符中(在正则表达式和替换中也需要仔细处理)。请参阅Is it possible to escape regex metacharacters reliably with sed 了解更多信息。

要将一个字符串替换为另一个字符串,最简单的方法是使用能够理解字符串的工具,例如 awk:

$ cat file
before stuff
foo @x@ bar
after stuff

$ cat tst.awk
BEGIN {
    old = ARGV[1]
    new = ARGV[2]
    ARGV[1] = ARGV[2] = ""
}
s = index($0,old) { $0 = substr($0,1,s-1) new substr($0,s+length(old)) }
{ print }

$ test='a/\t/&"b'

$ awk -f tst.awk '@x@' "$test" file
before stuff
foo a/\t/&"b bar
after stuff

无论test 包含什么字符,即使是换行符,上述内容都可以使用:

$ test='contains a
newline'
$ awk -f tst.awk '@x@' "$test" file
before stuff
foo contains a
newline bar
after stuff

【讨论】:

    【解决方案3】:

    如果您在 MacOS 上运行它并遇到 “正则表达式中的未终止替换”,对此有一个更简单的解释:

    MacOS 的 sed 版本与通常在 linux 上的版本稍有不同。 -i 需要一个参数。如果没有,只需在-i 后添加""

    sed -i "" --backup 's/@x@/'${test}'/g' file.json README.md
    

    或者例如,如果您只需要删除圆顶线,这适用于 linux,但在 MacOS 上会带来 “无效命令代码”

    sed -i 39d filenamehere.log
    

    这适用于 MacOS

    sed -i "" 39d filenamehere.log
    

    【讨论】:

      猜你喜欢
      • 2012-12-13
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      • 1970-01-01
      • 2019-10-10
      • 2021-11-20
      • 2012-04-26
      • 2015-11-30
      相关资源
      最近更新 更多