我想使用 sed 来匹配由 pattern1/pattern2 分隔的行 block ,然后仅对包含 pattern3 的 block 执行操作(例如打印 block ) >.
在下面的示例中,我在所有由匹配 { 和 } 的行分隔的 block 中寻找“如果你能 catch 我” em>(然后我想完整地打印匹配 block )。
我尝试过的:
sed -n -e '/{/,/}/{1h;1!{$!{H;d};H;x;/catch me if you can/p}}'
(思路是匹配由{和}分隔的 block ,然后将每个 block 累积到保持空间;在每个 block 的末尾,交换保持空间并为“如果可以的话 catch 我”)执行匹配。 这是行不通的,因为所有匹配的 block 一起被 sed 视为一个 block ,而不是单独处理每个 block 。
输入数据:
"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:每个 block 内字段的顺序是随机的。字段的数量和值的长度在 block 之间不是恒定的。我正在寻找的字段可能在某些 block 中丢失(而不是仅仅具有不同的值)。
注 2:出于教育目的,我更喜欢使用 sed 的解决方案,但如果那不可能,awk 或 bash 也可以。请不要使用 perl 或其他工具。
引用资料:
最佳答案
我就是这样做的。这里有两个版本,一个是BSD(Mac OS X)sed
(也适用于其他不运行GNU sed
的系统),一个是GNU sed
.
BSD 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
。 - 如果该行匹配
,将其添加到保留空间;切换模式并保持空间;如果模式空间(以前的保持空间)与您的其他模式匹配('如果可以的话 catch 我'),打印它;跳转到标签
next
。 - 将行添加到保留空间。
BSD(经典)sed
在 b next
之后的行中不需要任何内容,因此操作的 }
在下一行。
GNU 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"
}
关于bash - sed:如果与模式匹配,则打印分隔的行 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37357323/