2013-05-14 107 views
0

我有一个需要一些操作的大型数据库文件。基本上我需要避免重复的字段由'|'分隔为:awk - 仅打印第一行重复项和它下面的行

-- TITLE1 | TITLE2 |T3 |TITLE4|TITLE5 
----------|----------|-----|------|--------------- 
-- 
DATA1 | SAME  |  |  | blah blah 
ELIGIBLE | x1 
DATA1 | SAME  |  | blah | blah 
ELIGIBLE | x2 
DATA1 | SAME  |  | blah | blah blah 
ELIGIBLE | x2 
DATA2 | SAME  |  |  | blah blah 
ELIGIBLE | y1 
DATA2 | SAME  |  | blah | blah 
ELIGIBLE | y2 
DATA2 | SAME  |  | blah | blah blah blah blah 
ELIGIBLE | y2 
DATA3 | SAME  |  |  | blah blah 
ELIGIBLE | z1 
DATA3 | SAME  |  | blah | blah 
ELIGIBLE | z2 
DATA3 | SAME  |  | blah | blah blah blah blah 
ELIGIBLE | z2 

我使用的代码是

BEGIN{ FS = "|" } 
{ 
count[$1]++; 
if (count[$1] == 1) 
first [$1] = $0; 
if (count[$1] > 1) 
print first[$1] 
NR==1; 
} 

但它给我的输出:

-- TITLE1 | TITLE2 |T3 |TITLE4|TITLE5 
----------|----------|-----|------|--------------- 
-- 
DATA1 | SAME  |  |  | blah blah 
ELIGIBLE | x1 
DATA2 | SAME  |  |  | blah blah 
DATA3 | SAME  |  |  | blah blah 

我宁愿像这样的输出:

-- TITLE1 | TITLE2 |T3 |TITLE4|TITLE5 
----------|----------|-----|------|--------------- 
-- 
DATA1 | SAME  |  |  | blah blah 
ELIGIBLE | x1 
DATA2 | SAME  |  |  | blah blah 
ELIGIBLE | y1 
DATA3 | SAME  |  |  | blah blah 
ELIGIBLE | z1 

我并不关心标题栏,但n通过它来显示数据。对不起,业余解释,但任何解决方案的帮助,将不胜感激。我是新手,当涉及到Linux命令行脚本,所以如果任何人也可以解释为什么我的答案是错误的,我将不胜感激。我不局限于awk,并且可以使用任何命令解决方案。我只想用awk尝试解决方案。

+0

所以,你需要保留的数据的第一行与给定TITLE1扔掉剩下的,即使他们有不同的TITLE5的等? – 2013-05-14 15:14:19

+0

是正确的,并保留符合条件的行。 – 2013-05-14 15:40:03

回答

0

你可以试试这个:

awk -F\| '(printed!=0 && /ELIGIBLE/) {print; printed=0;} (!seen[$1] && $1 !~ /ELIGIBLE/) { print; printed = 1; seen[$1] = 1; }' 

虽然有几乎可以肯定是更好的方式。

ETA:在网络上有一个很好的Awk教程here和其他几个人,以及一些好书。但基本上,awk程序是一系列模式和代码块,以便在每个与该模式匹配的记录(缺省情况下为行)上运行。

awk '/foo/   { do this for lines that contain "foo" anywhere } 
    ($1 == "bar") { do this for lines whose first field is exactly "bar' } 
    ($NF ~ /baz/) { do this for lines whose last field contains "baz" } 
    (NF == 1)  { do this for lines with exactly one field } 
    (NR == 10)  { do this only on the 10th line }' 

如果没有图案,块会在每一行上运行。

awk '{print $NF}' # print the last field of every line 

如果没有块,只是一个图案,然后匹配的行被打印不变:

awk '/foo/'  # same as grep foo 

标记的任何输入被处理之前开始运行A嵌段;在处理完所有输入后运行标有END的块。

awk 'BEGIN { t = 0 } {t += $NF} END { print t }' # print total of last column 

但实际上未初始化变量视为算术0,这样你就可以跳过初始化:

awk '{t += $NF} END {print t}' 

AWK的一些版本需要模式/块对之间用分号;或换行

+0

该解决方案非常完美,非常感谢!你能解释一下如何使用awk排除/包含文本。对不起,我正在学习,只用它来进行字段匹配。 – 2013-05-14 17:23:14

+0

如果这回答了你的问题,你应该接受答案... – 2013-05-14 23:53:48

0

这条线适用于你给定的例子。 (数据被排序,在线数据,在线符合条件...)如果格式改变,不能保证为真实数据工作。你必须自己测试它。

标题/标题被跳过。

awk -F'|' '!(NR%2){next}$1 in a{next}{print;a[$1];getline;print}' file 

尝试:

kent$ awk -F'|' '!(NR%2){next}$1 in a{next}{print;a[$1];getline;print}' file 
DATA1 | SAME  |  |  | blah blah 
ELIGIBLE | x1 
DATA2 | SAME  |  |  | blah blah 
ELIGIBLE | y1 
DATA3 | SAME  |  |  | blah blah 
ELIGIBLE | z1