我有一个文件,其中包含这样的连续行
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,$H
为H;1h
。)
考虑到 don_crissti 的评论,我补充说解决此类问题的典型方法是循环N;P;D
:始终添加N
ext 行,一起处理两者,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 打印符合匹配模式的行