如何从单个文件中grep两列

时间:2013-09-20 05:46:44

标签: shell unix awk

cat Error00

4  0    375
4 2001   21
4 2002   20

cat Error01

4 0      465
4 2001   12
4 2002   40
4 2016   1

我想要输出如下

4 0      375   465
4 2001   21    12
4 2002   20    20
4 2016   -     1

我正在使用以下查询。这里的问题是我无法处理两个字段的grep因为空间即将到来。 请建议如何摆脱这个。

keylist=$(awk '{print $1,$2'} Error0[0-1] | sort | uniq)
for key in ${keylist} ; do
echo ${key}
        val_a=$(grep "^${key}" Error00 | awk  '{print $3}') ;val_a=${val_a:---}
        val_b=$(grep "^${key}" Error01 | awk '{print $1,$2}') ; val_b=${val_b:---    --}
        echo $key  ${val_a} >>testreport
done

我将oputput设置如下

4       375   465
0
4       21    12
2001
4       20    20
2002
4       -     1
2016

2 个答案:

答案 0 :(得分:4)

单个awk一个班轮可以轻松处理这个问题:

awk 'FNR==NR{a[$1,$2]=$3;next}{print $1,$2,(a[$1,$2]?a[$1,$2]:"-"),$3}' err0 err1
4 0 375 465
4 2001 21 12
4 2002 20 40
4 2016 - 1

对于格式化输出,您可以使用printf代替print。像Jonathan Leffler建议:

printf "%s %-6s %-6s %s\n",$1,$2,(a[$1,$2]?a[$1,$2]:"-"),$3
4 0      375    465
4 2001   21     12
4 2002   20     40
4 2016   -      1

然而,一般的解决方案是使用column -t作为一个很好的表输出:

awk '{....}' err0 err1 | column -t
4  0     375  465
4  2001  21   12
4  2002  20   40
4  2016  -    1

答案 1 :(得分:1)

grep并非真正适合这项工作的工具。您可以使用awk或Perl(或Python,或......),也可以使用join。但是,join一次只能连接一个列,并且您似乎需要连接两列。因此,我们将不得不按摩数据,以便它可以与join一起使用。我将假设您正在使用bash,因此process substitution可用。你可以在没有这项工作的情况下完成这项工作,但它更加繁琐,并且涉及临时文件(以及用于清理它们的陷阱等)。

连接的关键是用冒号(或任何其他方便的字符替换前两列之间的空白 - control-A也能正常工作),然后用第1列的文件加入替换字符。必须对输入进行排序;输出必须用空格替换冒号。

$ join -o 0,1.2,2.2 -a 1 -a 2 -e '-' \
>     <(sed 's/  */:/' Error00 | sort) \
>     <(sed 's/  */:/' Error01 | sort) |
> sed 's/:/ /'
4 0 375 465
4 2001 21 12
4 2002 20 40
4 2016 - 1
$

's/ */:/'操作用冒号替换一个或多个空格的第一个序列;输入数据在Error00的第一行中的4和0之间有两个空格。 join的输入必须按加入字段的排序顺序排列,此处为第一个字段。输出是连接字段,Error00的第二列和Error01的第二列(记住这意味着前两个列之后的第二列已被冒号融合)。如果第一个文件中有不匹配的行,则生成输出行(-a 1);同上第二个文件;对于缺少的字段,插入破折号(-e '-')。最后的sed删除了添加的冒号。

如果您希望格式化数据,请通过awk

进行管道传输
$ join -o 0,1.2,2.2 -a 1 -a 2 -e '-' \
>     <(sed 's/  */:/' Error00 | sort) \
>     <(sed 's/  */:/' Error01 | sort) |
> sed 's/:/ /' |
> awk '{printf("%s %-6s %-6s %s\n", $1, $2, $3, $4)}'
4 0      375    465
4 2001   21     12
4 2002   20     40
4 2016   -      1
$