【问题标题】:Use sed to take all lines containing regex and append to end of file使用 sed 获取包含正则表达式的所有行并附加到文件末尾
【发布时间】:2016-02-11 08:27:26
【问题描述】:

我正在尝试编写一个sed 脚本来获取包含模式的所有行并将它们移动到输出的末尾。这是一个学习保持与模式空间的练习,我正在努力想出它(尽管我感觉很接近)。

我在这里:

$ echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" | sed -E '/foo/H; //d; $G'
hi
bar
something
yo

foo1
foo2

但我希望输出是:

hi
bar
something
yo
foo1
foo2

我明白为什么会这样。这是因为我们第一次找到 foo 时,保留空间是空的,所以 H 将 \n 附加到空白保留空间,然后是第一个 foo,我认为这很好。但随后 $G 又做了一次,即另一个追加,它将\n 加上保持空间中的内容添加到模式空间。

我尝试了使用/^$/d 的最终删除命令,但没有删除空行(我认为这是因为该模式不是与最后一行匹配,而是与现在的多行模式空间匹配\n\n 在里面。

我确信sed 大师们有解决我的问题。

【问题讨论】:

  • 您为什么不发布您的解决方案作为答案?这实际上在这里受到鼓励。

标签: sed


【解决方案1】:

这可能对你有用(GNU sed):

sed '/foo/H;//!p;$!d;x;//s/.//p;d' file

如果该行包含所需的字符串,则将其附加到保留空间(HS),否则正常打印。如果它不是最后一行,则将其删除,否则将 HS 交换为模式空间 (PS)。如果所需的字符串现在在 PS 中(HS 是什么);由于添加了所有此类模式,因此第一个字符将是换行符,删除第一个字符并打印。删除剩下的。

另一种选择,使用-n 标志:

sed -n '/foo/H;//!p;$!b;x;//s/.//p' file

注意当db(不带参数)命令被执行时,没有进一步的 sed 命令,新的一行被读入 PS 并且 sed 脚本从第一个命令开始,即 sed 命令不会在前一个命令之后继续d 命令。

【讨论】:

  • 谢谢! //s/.//p 是做什么的?我看到它的方式是 s/.//p ,它表示匹配单个字符(在这种情况下为换行符)并将其替换为空并打印。但是前导 // 是为了什么?
  • 嗯,你能用 s 的“最后匹配的正则表达式”技巧吗?如果 PS 匹配 foo,// 是有效的 /foo/s/.//p,那么做这个替换?
【解决方案2】:

为什么?像这样的东西在 awk 中绝对是微不足道的,awk 在 sed 所在的任何地方都可用,并且生成的 awk 脚本将比 sed 脚本执行相同任务更简单、更便携、更快、更好。在 1970 年代中期之前,当 awk 被发明时,sed 中所有能够容纳空间的东西都是必需的,但现在除了作为一种心理锻炼之外,它绝对没有用处。

$ echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" |
    awk '/foo/{buf = buf $0 RS;next} {print} END{printf "%s",buf}'
hi
bar
something
yo
foo1
foo2

以上内容将在每个 UNIX 安装的每个 awk 中按原样工作,我敢打赌,您可以很容易地弄清楚它是如何工作的。

【讨论】:

    【解决方案3】:

    这感觉像是一个 hack,我认为应该可以更优雅地处理这种情况。以下适用于 GNU sed

    echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" | sed -r '/foo/{H;d;}; $G; s/\n\n/\n/g'
    

    但是,在 OSX/BSD sed 上,会导致这个奇怪的输出:

    hi
    bar
    something
    yonfoo1
    foo2
    

    请注意,两个连续的换行符已替换为文字字符 n

    解释了 OSX/BSD 与 GNU sed in this article。以下工作(在 GNU SED 中也是如此):

    echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" | sed '/foo/{H;d;}; $G; s/\n\n/\'$'\n''/' 
    

    TL;DR;在 BSD sed 中,它不接受替换表达式的 RHS 中的转义字符,因此您必须在命令行中放置一个真正的 LF/换行符,或者在您需要的地方拆分 sed 脚本字符串时执行上述操作RHS 上的换行符并在 '\n' 前面放一个美元符号,这样 shell interprets it as a line feed

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-18
      • 2021-01-10
      • 1970-01-01
      相关资源
      最近更新 更多