该块始终以:00 PROGRAM 开头
它以 XYZ 结尾,后跟一个空行。 XYZ 也出现在较早的行块中,但较早的行后面跟着更多数据。我只需要空行之前的最后一行。我还没有找到任何符合我意图的代码。我希望这对某人来说是一个简单的答案!
我确实想保留空白行之前的最后一行。例如:
000-12-22
AB1
00 PROGRAM
01 INQUIRY
03 XYZ
04 XYZ
blank line
LINE VALUE
00456
仅应删除这部分。
00 PROGRAM
01 INQUIRY
03 XYZ
答案1
这种类型的范围是完美的的用例ex
。 我有写了ex
很多在本网站上;它无疑是用于脚本文件编辑的最佳 POSIX 工具。
命令:
如果您只需要处理一个块,请使用:
printf '%s\n' '/00 PROGRAM/' '.,/^$/-2d' x | ex file.txt
如果可能有多个块,请使用:
printf '%s\n' 'g/00 PROGRAM/.,/^$/-2d' x | ex file.txt
为了进行测试,请使用%p
而不是x
:
printf '%s\n' '/00 PROGRAM/' '.,/^$/-2d' %p | ex file.txt
printf '%s\n' 'g/00 PROGRAM/.,/^$/-2d' %p | ex file.txt
这将打印整个缓冲区,而不是将缓冲区的内容保存回文件。
插图:
[vagrant@localhost ~]$ cat file.txt
000-12-22
AB1
00 PROGRAM
01 INQUIRY
03 XYZ
04 XYZ
LINE VALUE
00456
[vagrant@localhost ~]$ printf '%s\n' '/00 PROGRAM/' '.,/^$/-2d' x | ex file.txt
[vagrant@localhost ~]$ cat file.txt
000-12-22
AB1
04 XYZ
LINE VALUE
00456
[vagrant@localhost ~]$
解释和评论:
您可以使用ex -c 'editingcommands' filename
,但我发现这会产生比解决的问题更多的问题:如果遇到错误,ex
不会退出,而是会挂起等待用户输入。此外,以这种方式传递多个命令还存在潜在的可移植性问题ex
,因为 POSIX 不保证允许您这样做的常见功能。
相反,我通常将命令通过管道传输到ex
from printf
。这允许通过使用%s\n
格式字符串来轻松地换行分隔多个命令printf
,并且如果出现错误,它会使文件保持不变,而不会挂起(例如,如果您尝试编辑大于文件最后一行的行)。
为了在实际编辑文件之前测试命令,我使用%p
(打印整个缓冲区)作为最后一个命令。然后我可以稍微调整命令并一次又一次运行它,直到获得我想要的确切文件内容。一旦我对结果感到满意,我就会将其更改%p
为x
运行命令一有更多时间来实际保存对文件的更改。
这又是我为回答这个问题而给出的命令:
printf '%s\n' '/00 PROGRAM/' '.,/^$/-2d' x | ex file.txt
该printf
命令只是打印三个字符串/00 PROGRAM/
,.,/^$/-2d
并x
用换行符分隔,如下所示:
[vagrant@localhost ~]$ printf '%s\n' '/00 PROGRAM/' '.,/^$/-2d' x
/00 PROGRAM/
.,/^$/-2d
x
[vagrant@localhost ~]$
这三行是ex
命令。
ex
命令概述
命令ex
有两部分:地址(基于行)和命令。
如果只有一个地址,则光标将移动到该地址(移动到该行)。
如果只有命令,则使用当前行作为地址。
地址通常可以是范围— 一个地址,后跟一个逗号,然后是另一个地址。这是指从第一个地址到第二个地址的所有行。
地址可以是行号,但不一定是。它也可以是一个搜索模式,意思是“当前行之后与该正则表达式匹配的下一行”。您可以进行向后搜索以及向前搜索。
您甚至可以编写一个地址,表示“该实例之前的两行发生在最紧邻当前行之前foo
的实例之后”。bar
这看起来像:?bar?/foo/-2
一步步
该命令/00 PROGRAM/
只是一个地址,因此它的意思是“将光标移动到模式‘00 PROGRAM’的第一个实例”。
该命令.,/^$/-2d
有两个部分。最后d
的 是命令,意思是“删除”。剩下的就是地址了。
首字母.
是一个特殊的地址,引用当前行。
该模式/^$/
是空行的正则表达式(行首^
紧跟行尾$
)。在这种情况下,它意味着当前光标位置之后的下一个空行。
意思-2
是“向后两行”。
那么,所有这些都.,/^$/-2d
意味着:“删除从当前行到下一个空行上方两行的行。”
x
简单地说,将缓冲区内容保存到文件并退出编辑器。
希望这个对你有帮助。 ex
是一个非常强大的文本编辑工具。它是vi
“可视化编辑器”的前身。所有命令也ex
可以运行。vi
答案2
回答修改后的问题
让我们考虑这个测试文件;
$ cat File2
000-12-22
AB1
00 PROGRAM
01 INQUIRY
03 XYZ
04 XYZ
LINE VALUE
00456
尝试这个命令:
$ sed '/00 PROGRAM/,/^$/{/./{h;d}; x; p; x;}' File2
000-12-22
AB1
04 XYZ
LINE VA
卢埃00456
回答原来的问题
如果我理解正确,您有一个包含多组留置权的文件,这些留置权以包含空行的行开头00 PROGRAM
并以空行结束,并且如果包含XYZ
.如果是这种情况,请尝试以下操作:
sed -n '/00 PROGRAM/,/^$/{/./{h;d}; x;/XYZ/p}' file
例子
考虑这个示例文件:
$ cat file
00 PROGRAM
some
XYZ discard this
data
XYZ keep this
other
00 PROGRAM
more
XYZ keep this also
end
这仅保留XYZ
块中空行之前的行00 PROGRAM
:
$ sed -n '/00 PROGRAM/,/^$/{/./{h;d}; x;/XYZ/p}' file
XYZ keep this
XYZ keep this also
选择
也许,您希望保留组之外的所有行,并且如果匹配,还保留组的最后一个非空行XYZ
。在这种情况下:
$ sed '/00 PROGRAM/,/^$/{/./{h;d}; x;/XYZ/!d}' file
XYZ keep this
other
XYZ keep this also
end