【问题标题】:FreeBSD sed with newline and backslash in substituteFreeBSD sed 用换行符和反斜杠代替
【发布时间】:2016-08-08 13:53:30
【问题描述】:

由于在 FreeBSD 中实现的 sed 不支持替换模式中的任何转义序列,我必须使用 "\'$'\n" 来表示换行符和 "'$ '\n”。它确实支持“\”的反斜杠。

不幸的是,将换行符与反斜杠结合起来会导致我出错。例如,我想添加一行以制表符开头和“添加的行。\”在每行之后带有“key:\”,我写道:

#!/bin/bash
sed -E 's/^key:\\$/&\'$'\n'$'\tline added.\\/g' file

它给我一个错误,例如:

sed: 2: "s/^key:\\$/&\
    line add ...": unterminated substitute in regular expression

如何在 sed 的替换参数中同时使用换行符和反斜杠?

非常感谢!

【问题讨论】:

  • 你可以使用 var my_replacement 和类似 s/^key:\\$/&'"${my_replacement}""/' file 的东西吗?还是使用 awk?
  • FreeBSD 没有#!/bin/bash(除非是手动添加的),为了便于移植使用#!/bin/sh#!/usr/bin/env bash
  • This answer 涵盖了很多领域,包括 BSD sed 中的换行符。
  • 感谢您的提醒。它实际上是一个 FreeNAS 盒子,在 /bin 上有一个指向 /usr/local/bin/bash 的软链接。

标签: bash sed freebsd


【解决方案1】:

该示例失败,因为在最后一段中似乎无意引用了内容。

$'\tline added.\\/g'

$'...' 构造评估整个最后一部分,这意味着它处理 \\ 留下以 \/g 结尾的 sed 命令。

要获得预期的行为,要么终止 C 风格的转义,然后重新启动单引号字符串

$'\t''line added.\\/g'

或转义\\

$'\tline added.\\\\/g'

另一种方法是将整个命令包含在 $'...' 构造。

sed $'s/^key:\\$/&\\\\\\\n\tline added.\\\\/'

一种可移植的替代方法是使用文字字符、换行符和制表符。
(也许有评论澄清它是故意的)

sed 's/^key:\\$/&\\\
    line added.\\/'

为避免多次运行时出现重复,需要稍微复杂一点的脚本。
(注意n在最后一行运行会退出脚本)

sed '/^key:\\$/ {
    n
    /^  line added\.\\$/!i\
    line added.\\
}'

$'...' 出现在 FreeBSD sh、MirBSD kshksh93 (Illumos sh)、zshbash

【讨论】:

  • 非常感谢。我现在明白了。
  • 是否可以防止 sed 在连续运行时再次添加该行?谢谢!
  • @crackpot 是的,我在答案中添加了一个示例。
【解决方案2】:

您尝试使用错误的工具。 sed 用于在单个行上进行简单替换,仅此而已。对于其他任何事情,您都应该使用 awk。

to add a line starts with a tab and "line added.\" after every line with "key:\" 只是:

awk '{print} /key:\\/{print "\tline added.\\"}' file

以上内容适用于所有操作系统上的所有 awk。

在之前的后续运行中不这样做是:

awk -v n='\tline added:\\' 'p~/key:\\/ && $0!=n{print n} {print; p=$0}'

例如:

$ cat file1
foo
key:\
bar

$ awk -v n='\tline added:\\' 'p~/key:\\/ && $0!=n{print n} {print; p=$0}' file1 > file2

$ cat file2
foo
key:\
        line added:\
bar

$ awk -v n='\tline added:\\' 'p~/key:\\/ && $0!=n{print n} {print; p=$0}' file2
foo
key:\
        line added:\
bar

p 为旧版本,n 为新版本。上面的工作只是等到key:\\ 之后的行插入新行,并且只有在当前行还不是要插入的行时才进行插入。如果关键行可以出现在文件末尾,那么您需要测试关键行并在 END 语句中添加新行:END{if (p~/key:\\/) print n}

【讨论】:

  • 非常感谢。如您所说,sed只是单行操作的工具,是否可以在awk中编写可以防止它在连续运行时再次添加行?非常感谢!
  • 当然,这很简单,我已经编辑了我的答案来展示它。我看到您接受了 sed 的回答,所以我希望您会要求该发布者进行相同的增强,因为我期待看到如何增强 sed 脚本以处理此次要要求更新。 sed脚本更新后请给我留言,我记得过来看看,谢谢。
  • 非常感谢。 awk 起初对我来说似乎很复杂,我问的是 sed 用法的问题:因此,我认为 sed 的答案是正确的。我不知道我可以设置多个回复作为答案。对于那个很抱歉。在你告诉我之前,我不知道 awk 可以处理多行。那是鼓舞人心的!再次感谢您!
  • 如果您要进行更多的文本处理并且有 awk 可用(例如在任何 UNIX 安装上),我强烈建议您阅读 Arnold Robbins 的《Effective Awk Programming, 4th Edition》一书。
  • 谢谢,我去看看!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 2011-10-14
  • 1970-01-01
  • 1970-01-01
  • 2018-01-29
  • 2012-04-14
  • 2012-06-16
相关资源
最近更新 更多