1

I have files with lines such as:

Data;moreData;EvenMoreData1;200
Data;moreData;EvenMoreData1;200

Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0

Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0

Basically Every 2 lines are related to each other. Im trying to find the best way to only print the lines with a single 0 and the line above or below it. So the output would be like.

Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0

Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0
4

4 回答 4

7
$ perl -00 -ne "print if /;0$/m;" < input
0;Data;0;moreData;EvenMoreData2;500
0;Data;0;moreData;EvenMoreData2;0

0;Data;0;moreData;EvenMoreData3;0
0;Data;0;moreData;EvenMoreData3;0

0;Data;0;moreData;EvenMoreData3;0
0;Data;0;moreData;EvenMoreData3;1

-00打开段落模式,将输入记录分隔符设置为\n\n+,因此这取决于两个数据行之间的空行。

$ cat input
0;Data;0;moreData;EvenMoreData1;200
0;Data;0;moreData;EvenMoreData1;200

0;Data;0;moreData;EvenMoreData2;500
0;Data;0;moreData;EvenMoreData2;0

0;Data;0;moreData;EvenMoreData3;0
0;Data;0;moreData;EvenMoreData3;0

0;Data;0;moreData;EvenMoreData3;0
0;Data;0;moreData;EvenMoreData3;1
于 2013-05-04T17:27:40.100 回答
1

这可能对您有用(GNU sed):

sed -r 'N;N;/;0(\n|$)/p;d' file
于 2013-05-05T00:42:47.860 回答
1

只需告诉 awk 记录由空行 ( -v RS=) 分隔,字段由换行符 ( -F'\n') 分隔,然后检查记录中任何行末尾的“;0”:

$ awk -v RS= -v ORS='\n\n' -F'\n' '/;0(\n|$)/' file
Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0

Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0

将 ORS 设置为 2 个换行符 ( -v ORS='\n\n') 只是告诉 awk 在输出记录之间放置一个空行,以便它看起来像您的输入格式。如果你不在乎,就不要设置 ORS,你会得到更简单的:

$ awk -v RS= -F'\n' '/;0(\n|$)/' file
Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0
Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0

仅供参考,这将适用于您记录中的任意数量的行。

作为回应要求进一步解释的评论:

awk 是基于记录的,不像 sed 是基于行的。awk 的默认记录分隔符是换行符,因此默认情况下 awk 在行上工作,就像 sed 一样,但是通过更改记录分隔符(内置 RS 变量),您可以让 awk 处理您喜欢的任何文本块。特别是当您将 RS 设置为 NULL 字符串时,awk 记录由空行分隔。

因此,在这种特殊情况下,-v RS=将 RS 设置为 NULL 字符串,以便 awk 将输入处理为 3 条记录:

记录 1)

Data;moreData;EvenMoreData1;200
Data;moreData;EvenMoreData1;200

记录 2)

Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0

记录 3)

Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0

awk by dafault 将记录分成由空格链分隔的字段,但您可以通过设置内置的字段分隔符变量 FS 来更改该行为。在这种情况下,我将 FS 设置为换行符,-F'\n'这意味着上述每个记录都被视为 2 个字段:

记录 1,字段 1)

Data;moreData;EvenMoreData1;200

记录 1,字段 2)

Data;moreData;EvenMoreData1;200

记录 2,字段 1)

Data;moreData;EvenMoreData2;500

记录 2,字段 1)

Data;moreData;EvenMoreData2;0

记录 3,字段 1)

Data;moreData;EvenMoreData3;0

记录 3,字段 2)

Data;moreData;EvenMoreData3;0

现在我已经到了这一点,我意识到我根本不需要设置 FS,因为我最终使用的正则表达式对整个记录而不是单个字段进行操作,所以这实际上就是我所需要的:

$ awk -v RS= -v ORS='\n\n' '/;0(\n|$)/' file
Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0

Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0

它只是在由“\n”标识的任何行的末尾(例如,在每条记录的第 1 行的末尾)或由“$”标识的记录的末尾寻找正则表达式“;0”(例如,在每条记录的第 2 行末尾,因此 /;0(\n|$)/ 将在记录中任何行的末尾找到“;0”。

希望对我有所帮助,并为在我不需要时设置 FS 造成的混乱道歉,这是我第一次开始研究这个问题时的产物。

对于高尔夫球手:

$ awk '/;0(\n|$)/' RS= file
Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0
Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0
于 2013-05-05T12:35:11.300 回答
-1
$ awk -F';' 'NR%3!=0{f=$NF;a=$0;getline;if(f==0||$NF==0)print a"\n"$0"\n"}' file
Data;moreData;EvenMoreData2;500
Data;moreData;EvenMoreData2;0

Data;moreData;EvenMoreData3;0
Data;moreData;EvenMoreData3;0
于 2013-05-04T17:36:07.250 回答