grep / awk stdin限制?

时间:2014-06-17 18:53:01

标签: bash awk grep stdin

我环顾四周,但我找不到任何已经回答此问题的人。

我正在编写一个bash脚本,它将读取6个不同的csv个文件,并计算所有文件中有多少行一起包含某些标记。

(它是一个联系人列表数据库 - 还有商业或私人电子邮件地址的标签)

以下是我编写的代码示例:

### First Scan - Business emails ###

bus="$(awk 'BEGIN {FS = ","}{print $27}' FILE*full* | grep -c "Business")"

echo "No. of Business Accounts: $bus"

### Second Scan - Private emails ###

priv="$(awk 'BEGIN {FS = ","}{print $27}' FILE*full* | grep -c "Private")"

echo "No. of Private Accounts: $priv"

脚本返回看似完全正确的值。然而!我知道每个文件中的每一行都有标记' business'或者'私人'在相同的位置 - 并没有空行,但当我将两个结果加在一起时,它不等于完整的行数......大约有45000个缺失......

stdingrep的{​​{1}}是否有任何限制 - 完整的数据库超过200万行......

请帮忙! : - )

2 个答案:

答案 0 :(得分:5)

最有可能的是,数百万行csv中的一些包含带引号的带引号的字段。 Awk对引用一无所知;它会以逗号分开。

如果您正在使用Gnu awk,则可以使用FPAT变量,该变量允许您为字段指定正则表达式,而不是字段分隔符的正则表达式。例如,这将适用于许多CSV文件(如果csv文件使用CR-LF行结尾,则除了行结束问题)。 (-v var=value大致相当于BEGIN{var="value"},而不仅仅是Gnu awk。)

gawk -v FPAT='[^",][^,]*|("[^"]*")*'  

顺便说一句,没有必要使用grepawk。您可以使用awk过滤和计数;实际上,您可以在同一扫描中执行两个计数:

gawk -v FPAT='[^",][^,]*|("[^"]*")*' '
     $27 ~ /Business/ {++bus}
     $27 ~ /Private/  {++pri}
     END { print "No. of Business accounts", bus
           print "No. of Private accounts", pri}' FILE*full* 

上面的正则表达式非常简单,它不会处理"错误的" CSV文件(如果您可以将这个词用于这种松散定义的格式)。匹配:

[^",][^,]*|("[^"]*")*
  |    |  | |  |  | |
  +----+--+-+--+--+-+----- A character other than quote or comma
       |  | |  |  | |
       +--+-+--+--+-+----- Followed by any number of characters other than comma
          | |  |  | |
          +-+--+--+-+--- OR
            |  |  | |
            |  |  | +----- Any number of sequences consisting of
            |  |  |
            +--+--+--------- A quote
               |  |
               +--+--------- Any number of characters other than a quote
                  |
                  +--------- Another quote

因此,第一个替代方案将匹配未加引号的字段,例如93.7Private,第二个替代方案将匹配:

  • 引用字段,可能包括逗号:"Blood, sweat and tears"

  • 根据引用加倍规则引用带有内部引号的字段:"""My goodness,"" she said"(请参阅RFC 4180的第2.7节。)

它没有尝试匹配反斜杠转义的引号,它们不是标准的一部分(它们也不是由MS Excel生成的,afaik),如果引用的字段错误地包含一个不加引用的引号,它将完全失败

您可以在上面的程序中使用一个简单的变体来查看未正确解析的行,这可能会让您修复它们,或者调整正则表达式,如:

gawk -v FPAT='[^",][^,]*|("[^"]*")*' '
     $27 !~ /Business/ && $27 !~ /Private/ {
           print "----"
           print "Error at line " NR:
           print $0
           for (i=1; i<=NF; ++i) printf "%2d: |%s|\n", i, $i
     }' filename

答案 1 :(得分:1)

试试这个并告诉我们你得到了什么输出:

awk -F',' '
$27 ~ /Business/ { bus++; next }
$27 ~ /Private/  { priv++; next }
{ other++; print "Non-Business/Private:", FILENAME, FNR, $27 }
END { print NR, bus, priv, other }
' FILE*full*

上面输出中的NR代表总记录,应该等于bus + priv + other。