[英]grep/awk stdin Limitations?
我環顧四周,但找不到任何已回答此問題的人。
我正在編寫一個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”或“ private”-並且沒有空行,但是當我將兩個結果加在一起時,它並不等於行的總數...大約有45000人失蹤...
grep
或awk
的stdin
是否有任何限制-完整的數據庫長度超過200萬行...
請幫忙! :-)
最有可能的是,在數百萬的csv行中,有一些包含帶引號的字段,並帶有逗號。 Awk對報價一無所知。 它只會以逗號分隔。
如果使用的是Gnu awk,則可以使用FPAT
變量,該變量使您可以為字段指定正則表達式,而不是為字段分隔符指定正則表達式。 例如,這將適用於許多CSV文件(除了csv文件使用CR-LF行尾的行尾問題之外)。 ( -v var=value
大致等效於BEGIN{var="value"}
,而不僅僅是Gnu awk。)
gawk -v FPAT='[^",][^,]*|("[^"]*")*'
順便說一句,不需要使用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*
上面的正則表達式非常簡單,並且不會處理“不正確”的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.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
試試這個,告訴我們您得到什么輸出:
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。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.