asi*_*ght 1 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"
Run Code Online (Sandbox Code Playgroud)
该脚本返回看似完全正确的值.然而!我知道一个事实,每个文件中的每一行都有标记'business'或'private'在同一位置 - 并且没有空行但是当我将两个结果一起添加时,它不等于完整的行数...大约有45000个失踪......
有没有到任何限制stdin的grep或awk-全数据库超过200万线长...
请帮忙!:-)
最有可能的是,数百万行csv中的一些包括带引号的带引号的字段.Awk对引用一无所知; 它只会在逗号上分开.
如果您正在使用Gnu awk,则可以使用该FPAT变量,该变量允许您为字段指定正则表达式,而不是字段分隔符的正则表达式.例如,这将适用于许多CSV文件(如果csv文件使用CR-LF行结尾,则除了行结束问题).(-v var=value大致相当于BEGIN{var="value"},而不仅仅是在Gnu awk中.)
gawk -v FPAT='[^",][^,]*|("[^"]*")*'
Run Code Online (Sandbox Code Playgroud)
顺便说一句,有没有必要使用grep以及awk.您可以使用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*
Run Code Online (Sandbox Code Playgroud)
上面的正则表达式非常简单,它不会处理"不正确"的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
Run Code Online (Sandbox Code Playgroud)
因此,第一个替代方案将匹配未加引号的字段,如93.7或Private,第二个替代方案将匹配:
引用字段,可能包括逗号: "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
Run Code Online (Sandbox Code Playgroud)