[英]Removing a delimited block of lines when one of them matches a regex pattern with awk
[英]sed: print delimited block of lines if it matches a pattern
我想用sed以匹配模式1 / PATTERN2分隔的行的块,然后执行操作仅在包含pattern3块(例如打印块)。
在下面的示例中,我正在寻找“ 抓住我,如果可以的话 ”,在由匹配{和}的行分隔的所有块中(然后我想要完整地打印匹配的块)。
我尝试过的:
sed -n -e '/{/,/}/{1h;1!{$!{H;d};H;x;/catch me if you can/p}}'
(想法是匹配由{和}分隔的块,然后将每个块累积到保留空间;在每个块的末尾,交换保持空间并执行匹配以“ 抓住我,如果可以的话 ”)。 这不起作用,因为所有匹配的块一起被sed视为单个块,而不是单独处理每个块。
输入数据 :
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block2": {
"bbb": "24680",
"bar": "blah",
"foo": "argh",
"ccc": "135"
},
"block3": {
"ddd": "zzz"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
期望的输出 :
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can"
},
注1:每个块内的字段顺序是随机的。 字段数和值的长度在块之间不是恒定的。 我正在寻找的字段可能在某些块中丢失(而不是仅具有不同的值)。
注2:出于教育目的, 我更喜欢使用sed的解决方案 ,但如果不可能,awk或bash也可以。 请不要使用perl或其他工具。
参考文献:
我就是这样做的。 这里有两个版本,一个用于BSD(Mac OS X) sed
(也适用于其他未运行GNU sed
系统),另一个用于GNU sed
。
sed
$ cat script.bsd-sed
/{/,/}/{
/{/{ h; b next
}
/}/{ H; x; /catch me if you can/p; b next
}
H
:next
}
$ sed -n -f script.bsd-sed data
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
$
逻辑是:
-n
),否则不要打印任何内容。 {
和}
行之间 {
,则将该模式复制到保留空间并跳转到next
标签。 }
,则将其添加到保留空间; 切换模式并保持空间; 如果图案空间(先前保持空间)与您的其他图案匹配(如果可以,请抓住我),打印它; 跳转到标记next
。 BSD(经典) sed
在b next
之后的行上不需要任何内容,因此动作的}
在下一行。
sed
$ cat script.gnu-sed
/{/,/}/{
/{/{ h; b next }
/}/{ H; x; /catch me if you can/p; b next }
H
:next
}
$ /opt/gnu/bin/sed -n -f script.gnu-sed data
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
$
GNU sed
在标签终止命令后识别分号或闭括号,因此它允许更紧凑的表示法。 你甚至可以将它们整合成一行 - 你必须添加几个分号:
$ /opt/gnu/bin/sed -n -e '/{/,/}/{ /{/{ h; b next }; /}/{ H; x; /catch me if you can/p; b next }; H; :next }' data
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
$
您也可以删除不在模式匹配中的空格:
$ /opt/gnu/bin/sed -n -e '/{/,/}/{/{/{ h;b next};/}/{H;x;/catch me if you can/p;b next};H;:next}' data
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
$
data
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block2": {
"bbb": "24680",
"bar": "blah",
"foo": "argh",
"ccc": "135"
},
"block3": {
"ddd": "zzz"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
"block5": [
"oops": "catch me if you can"
],
"block6": {
"rhubarb": "dandelion"
}
$ sed -n '/^"/{x;/catch/p;d}; ${H;x;/catch/p;d}; H' file
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
-n
除非我们要求,否则此选项告诉sed不要打印任何内容
/^"/{x;/catch/p;d}
对于以引号开头的任何行,这(1)交换模式并保持空间,(2)检查模式空间中现在的内容是否已catch
,如果是,则打印它,以及(3)删除模式空间,sed开始在下一行上工作。
${H;x;/catch/p;d}
当我们到达最后一行时,我们会做类似的事情。 我们将最后一行添加到保留空间,将保留空间交换到模式空间,检查它是否包含catch
,如果是,则打印它。 然后删除模式空间。
H
对于任何其他情况,该行将附加到保留空间。
$ awk '/catch/{print $0 "},"}' RS='}' file
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
,
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
},
Jonathan Leffler增加了方括号块的可能性以及大括号块,如他的测试文件data
。 在sed的情况下,尝试:
$ sed -n '/^"/{x;/{.*catch/p;d}; ${H;x;/{.*catch/p;d}; H' data
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
而对于awk:
$ awk '{s=(s?s"\n":"") $0} /{/{f=1} f && /catch/{f=2} /^[]}]/{if (f==2) print s; f=0; s=""} ' data
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
sed用于单个行上的简单替换, 即全部 。 在40年前发明awk时,所有比s,g和p(带-n)更多的结构都变得过时了。
使用GNU awk进行多字符RS和RT:
$ awk -v RS='},?\n' -v ORS= '/catch me if you can/{print $0 RT}' file
"block1": {
"foo": "abcd",
"bar": "catch me if you can",
"aaa": "12345"
},
"block4": {
"foo": "xyz",
"bar": "catch me if you can",
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.