Bash 提取两个图案之间的线条,并使用if条件删除线条之间的线条
我有一个包含以下内容的文件。我试图提取具有匹配的开始和结束模式的块,在这两者之间,我想排除具有不匹配的数字id(可能是模式)的块。此处必须排除[001]以外的内容。002可能不知道。因此,我只希望块与[001]匹配 文件包含:Bash 提取两个图案之间的线条,并使用if条件删除线条之间的线条,bash,shell,awk,sed,Bash,Shell,Awk,Sed,我有一个包含以下内容的文件。我试图提取具有匹配的开始和结束模式的块,在这两者之间,我想排除具有不匹配的数字id(可能是模式)的块。此处必须排除[001]以外的内容。002可能不知道。因此,我只希望块与[001]匹配 文件包含: text [001] start line 1 line 2 text [002] mid start line 3 line 4 text [002] mid end line 5 lin
text [001] start
line 1
line 2
text [002] mid start
line 3
line 4
text [002] mid end
line 5
line 6
text [001] end
我需要块,不包括不匹配的数字id[002]的块
text [001] start
line 1
line 2
line 5
line 6
text [001] end
对于这个问题,我无法在互联网上得到明确的澄清。有人能帮助我们解决这个问题吗,awk或sed解决方案
要获得具有开始和结束模式的块,我尝试使用
awk '/[001]/ && /start/, /001/ && /end/' File
使用sed或Perl:
sed '/001.*start/,/001.*end/!d;/002.*start/,/002.*end/d'
perl -ne 'print if /001.*start/ .. /001.*end/
and not /002.*start/ .. /002.*end/'
使用前瞻断言可以轻松地使排除的标记动态化:
perl -ne 'print if /001.*start/ .. /001.*end/
and not /text \[(?!001).*start/ .. /text \[(?!001).*end/'
使用sed或Perl:
sed '/001.*start/,/001.*end/!d;/002.*start/,/002.*end/d'
perl -ne 'print if /001.*start/ .. /001.*end/
and not /002.*start/ .. /002.*end/'
使用前瞻断言可以轻松地使排除的标记动态化:
perl -ne 'print if /001.*start/ .. /001.*end/
and not /text \[(?!001).*start/ .. /text \[(?!001).*end/'
这个
awk
可以。您可能需要调整触发器以处理数据:
awk '/\[001\] start/{f=1} /\[002\] .* start/{f=0} f; /\[001\] end/{f=0} /\[002\] .* end/{f=1}' file
text [001] start
line 1
line 2
line 5
line 6
text [001] end
可读性更强
awk '
/\[001\].*start/ {f=1}
/\[002\].*start/ {f=0}
f;
/\[001\].*end/ {f=0}
/\[002\].*end/ {f=1}
' file
只需更改触发器代码以反映真实数据。此
awk
可能就可以了。您可能需要调整触发器以处理数据:
awk '/\[001\] start/{f=1} /\[002\] .* start/{f=0} f; /\[001\] end/{f=0} /\[002\] .* end/{f=1}' file
text [001] start
line 1
line 2
line 5
line 6
text [001] end
可读性更强
awk '
/\[001\].*start/ {f=1}
/\[002\].*start/ {f=0}
f;
/\[001\].*end/ {f=0}
/\[002\].*end/ {f=1}
' file
只需更改触发代码以反映真实数据。假设我们使用变量
b1
(如果我们在块1中)和b2
(如果我们在块2中):
awk '/001/ && /start/ { b1=1 }
/002/ && /start/ { b2=1 }
(b1 && !b2)
/002/ && /end/ { b2=0 }
/001/ && /end/ { b1=0 }' file
范围表达式很方便,但请记住:永远不要使用范围表达式(例如,
/start/,/end/
)因为它们使琐碎的任务变得非常简短,但随后需要重复的条件或对最微小的需求更改进行完全重写。假设我们使用变量b1
(如果我们在块1中)和b2
(如果我们在块2中):
awk '/001/ && /start/ { b1=1 }
/002/ && /start/ { b2=1 }
(b1 && !b2)
/002/ && /end/ { b2=0 }
/001/ && /end/ { b1=0 }' file
范围表达式很方便,但请引述:永远不要使用范围表达式(例如,
/start/,/end/
),因为它们使琐碎的任务变得非常简单,但随后需要重复的条件或完全重写以满足最微小的需求更改。假设您的块嵌套到任何深度,并且从不重叠:
$ cat tst.awk
BEGIN { tgtId="001" }
match($0,/\[[0-9]+\]/) {
id = substr($0,RSTART+1,RLENGTH-2)
state = $NF
}
state == "start" { isTgtBlock[++depth] = (id == tgtId ? 1 : 0) }
isTgtBlock[depth] { print }
state == "end" { --depth }
{ id = state = "" }
$ awk -f tst.awk file
text [001] start
line 1
line 2
line 5
line 6
text [001] end
假设块嵌套到任意深度,并且从不重叠:
$ cat tst.awk
BEGIN { tgtId="001" }
match($0,/\[[0-9]+\]/) {
id = substr($0,RSTART+1,RLENGTH-2)
state = $NF
}
state == "start" { isTgtBlock[++depth] = (id == tgtId ? 1 : 0) }
isTgtBlock[depth] { print }
state == "end" { --depth }
{ id = state = "" }
$ awk -f tst.awk file
text [001] start
line 1
line 2
line 5
line 6
text [001] end
这可能适用于您(GNU-sed):
仅打印[001]
分隔符之间的行,并排除[002]
分隔符之间的行。这可能适用于您(GNU-sed):
仅打印
[001]
分隔符之间的行,并排除[002]
分隔符之间的行。如何找到001块,您假设只删除002块。啊哈!非代表性样本输入。它写在OPs post中:我试图提取具有匹配开始和结束模式的块
。这将被更新。也许我对“提取”的理解太宽泛了。你能建议一个适用于任何其他内部块的解决方案吗?。这里可能会有所不同。所以,我需要移除001以外的块。表示,以002为模式可能不适合@如何找到001块,假设只需要删除002块。啊哈!非代表性样本输入。它写在OPs post中:我试图提取具有匹配开始和结束模式的块
。这将被更新。也许我对“提取”的理解太宽泛了。你能建议一个适用于任何其他内部块的解决方案吗?。这里可能会有所不同。所以,我需要移除001以外的块。表示,以002为模式可能不适合@如果001和002的角色颠倒了怎么办?@kvantour我想这只是一个示例代码。他需要一个数据块,在该块中有一些东西需要删除。我认为除了001
之外的任何数字都可以出现在该块中,并且这些“子块”应该被删除。而不是子块,它可能被称为位于某个块中的具有不匹配数字id的块。这里001是需要的块,002是不匹配的块@WiktorStribiżew@Megkcalb所以答案中没有一个对你有帮助。不给予+1或接受1?如果001和002的角色颠倒了怎么办?@kvantour我想这只是一个示例代码。他需要一个数据块,在该块中有一些东西需要删除。我认为除了001
之外的任何数字都可以出现在该块中,并且这些“子块”应该被删除。而不是子块,它可能被称为位于某个块中的具有不匹配数字id的块。这里001是需要的块,002是不匹配的块@WiktorStribiżew@Megkcalb所以答案中没有一个对你有帮助。不给出+1或接受+1?如果块002在块001之后结束怎么办。您和min都将在重叠块中失败。。。迷人的。这将仍然打印块1中不属于块2的所有内容。如果块002在块001之后结束,该怎么办。您和min都将在重叠块中失败。。。迷人的。这将仍然打印块1中不属于块2的所有内容。