使用 sed 编辑两行字符串

使用 sed 编辑两行字符串

我有一个文件,其中包含这样的连续行

macroa{abc def 123 ghi}
macrob{abc 123 xyz}

我想检查 Macrob 中的第一个字符串是否与 Macroa 中的相同,以及是否删除它,所以结果是

macroa{abc def 123 ghi}
macrob{123 xyz}

我正在使用整个文件方法这里我的命令是

sed -e '1h;2,$H;$!d;g' -e 's/\(macroa{\([a-z]*\) [^\n]*\)\n\(macrob{\)\2 /\1\n\3/g' in > out

然而这不起作用。我做错了什么谢谢。

答案1

我用 GNU 测试了你的脚本sed,它产生了预期的结果。但是,这不能移植到其他sed版本,因为您\n在内部[]和替换中使用,这是标准未定义的。

在替换中使用它可以很容易地避免:

sed -e '1h;2,$H;$!d;g' -e 's/\(macroa{\([a-z]*\) [^\n]*\)\(\nmacrob{\)\2 /\1\3/g'

要在表达式中使用它[]可以通过一个技巧来完成 - 您使用该y命令在替换之前将换行符与普通字符交换,然后将其更改回来;在这种情况下我使用|

sed -e '1h;2,$H;$!d;g' -e 'y/\n|/|\n/;s/\(macroa{\([a-z]*\) [^|]*\)\(|macrob{\)\2 /\1\3/g;y/\n|/|\n/'

这是通用的解决方案,但我认为它很丑陋。在大多数情况下,[^\n]您可以编写,而不是[[:print:]],因为通常除换行符之外的所有代码都包含可打印字符,因此它是:

sed 'H;1h;$!d;g;s/\(macroa{\([a-z]*\) [[:print:]]*\)\n\(macrob{\)\2 /\1\n\3/g'

(我还将您的首字母简化1h;2,$HH;1h。)

考虑到 don_crissti 的评论,我补充说解决此类问题的典型方法是循环N;P;D:始终添加Next 行,一起处理两者,P打印第一行并将D其从模式空间中删除以继续第二行:

sed 'N;s/\(macroa{\)\([a-z]* \)\(.*\nmacrob{\)\2/\1\2\3/;P;D'

答案2

如果可以使用awk而不是sed

$ awk -F'[{ ]' 'c && c-- && $1=="macrob" && $2==s{sub(s" ", "")}
                $1=="macroa"{c=1; s=$2} 1' ip.txt
macroa{abc def 123 ghi}
macrob{123 xyz}
  • -F'[{ ]'使用{或空格字符作为字段分隔符
  • $1=="macroa"{c=1; s=$2}如果第一个字段是macroa,则使用 初始化计数器1并将第二个字段保存在变量中。计数器确定必须检查以下哪些行
  • c && c--只要计数器不为零,这就是正确的。因为c=1在这种情况下,只有一旦这是真的并且无论进一步的条件如何,计数器都会变为零。所以,只有连续的行才能匹配
  • $1=="macrob" && $2==s所需条件
    • sub(s" ", "")删除字符串和空格字符
  • 进一步阅读:使用 sed 或 awk 打印符合匹配模式的行

相关内容