2013-05-03 61 views
0

这里是我的示例清单:如果脚本正在逐行处理,如何返回以处理前一行?

AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III1   <----- I want to remove this 
GGG HHH III3 >>updated <----- I want to keep this 
JJJ KKK LLL7 

,因为我遍历使用for循环,我想利用具有“>>更新”中,并返回一个行的每一行的笔记列表并删除旧行(未更新),然后向前移动到“>>更新”行之后的下一行。所以基本上我的最终输出将是:

AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 

我使用awk来解析从shell脚本其他字段的值,但我只是不太清楚如何做到这一点向后和向前的一步。任何帮助将不胜感激。

+1

向我们展示迄今为止已编码的awk,这将是一个很好的开始来帮助你。 – fedorqui 2013-05-03 09:57:10

+0

真正的名单有多大?如果它不是太大,那么一个可能的解决方案是将整个批量读入一个数组中。随机访问很容易。 – cdarke 2013-05-03 10:01:13

+1

那么实际的专栏是很丑陋的。他们不完全排队,有些领域是空的,我也必须从列A到列E等替换一些领域... – fembot 2013-05-03 10:07:58

回答

5
awk '{a=$0;getline; if ($0~/>>updated/)print $1,$2,$3; else print a,"\n"$0}' file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 
+0

再次@sudo_O所以我实际上正在阅读一个文件,做一个'对于我在'cat myfile'循环中依次读取它,并使用awk解析每行中的每个字段并将输出写入临时文件。根据上面的建议,我是否应该通过一遍并将所有内容写入文件,然后使用tac cmd再次进行检查? – fembot 2013-05-03 10:02:24

+1

呃,循环访问文件的正确方法是'while read i;做...完成 tripleee 2013-05-03 10:10:27

+0

@tripleee我也可以做到这一点:)但仍然不能解决我的问题,当我到达有匹配“>>更新”字段的行时,我该如何返回一行,用新行替换旧行的内容。 – fembot 2013-05-03 10:13:27

4

这可能为你工作(GNU SED):

sed -r '$!N;s/.*\n(.*)\s+>>updated\s*$/\1/;P;D' file 

请模式空间两条直线和删除当最后的比赛,你的要求第一。

一个AWK解决方案可能是:

awk 'sub(/ *>>updated.*/,""){l=$0;next};NR>1{print l};{l=$0};END{print l}' file 
+0

我对sed有点粗糙。我知道如何进行替换,但目前为止我只用一行代码完成替换。如何在模式空间中保留两行? – fembot 2013-05-03 10:17:02

+1

@fembot sed命令'N'将下一行读入模式空间,并用换行符'\ n'将它与当前行分开。命令'$!N'表示除了最后一行总是在下一行读取。与'P'和'D'结合使用,可以打印/删除第一个换行符,这些命令允许sed在流过文件时处理2行窗口。 – potong 2013-05-03 10:35:59

+0

谢谢,我现在要去玩这个游戏。 – fembot 2013-05-03 10:37:10

3

tac是好的,但不是默认为所有发行。如果你没有它用,这里是一个awk单个进程的一行:

awk -F' >>' 'p{if($2~/updated/){p=$1;next}print p}{p=$0}END{print p}' file 
+0

我错误地回答了我的初始查询。如果我的当前行是“>>更新”,我想删除它之前的行,并将其替换为“>>更新”行中的值。 – fembot 2013-05-03 11:18:39

+0

@fembot我的脚本完成你所说的内容,输出与你的问题完全一样。 – Kent 2013-05-03 11:31:00

+0

+1如果记忆是一个重大问题,则采用正确的方法。 – 2013-05-03 12:22:49

1
perl -lne 'if(/\>\>updated/){pop @a;s/\>\>updated//g;push @a,$_}else{push @a,$_}END{print join "\n",@a}' your_file 

测试:

> cat temp 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III1 
GGG HHH III3 >>updated 
JJJ KKK LLL7 
> perl -lne 'if(/\>\>updated/){pop @a;s/\>\>updated//g;push @a,$_}else{push @a,$_}END{print join "\n",@a}' temp 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 
> 
+0

谢谢!这也工作! – fembot 2013-05-04 11:38:07

1

最简单的方法是建立的一个数组在你的输入文件中只有一行,但只有当>>更新不存在时才会增加数组索引,这样包含更新的行将覆盖数组中的前一个条目,然后在到达文件结尾时仅打印数组的内容:

$ cat file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III1   <----- I want to remove this 
GGG HHH III3 >>updated <----- I want to keep this 
JJJ KKK LLL7 

$ awk '!/>>updated/{++numLines} {line[numLines]=$0} END {for (nr=1;nr<=numLines;nr++) print line[nr]}' file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 >>updated <----- I want to keep this 
JJJ KKK LLL7 

如果你想摆脱在该行的更新>>和随后的文字,你可以为它的存在改变测试的测试,试图将其删除:

$ awk '!sub(/ *>>updated.*/,""){++numLines} {line[numLines]=$0} END{for (nr=1;nr<=numLines;nr++) print line[nr]}' file 
AAA BBB CCC1 
DDD EEE FFF1 
GGG HHH III3 
JJJ KKK LLL7 

如果>>更新是存在的然后sub()将它删除并返回成功,所以你知道>>更新是存在的,否则sub()将什么也不做,但返回失败,所以你知道>>更新是缺席。

相关问题