我想解析一个可能包含10万行的CSV文件。这是我的要求:
- 标识符的索引
- 标识符的值
我想检索在CSV中所有具有给定索引(由逗号分隔)和给定值的行。
您有什么建议,特别考虑性能?
cut
或awk
的一行代码的替代方案,您可以使用专业的csvtool
,也称为ocaml-csv
:$ csvtool -t ',' col "$index" - < csvfile | grep "$value"
csvtool
。当您需要使用标准工具时,这可能会成为一个问题。 - BugHunterUKsudo apt-get install csvtool
,然后运行csvtool --help
,因为手册内容有点少。 - ErichBSchulzBob Brown;Manager;16581;Main
Sally Seaforth;Director;4678;HOME
Bash脚本:
#!/bin/bash
OLDIFS=$IFS
IFS=";"
while read user job uid location
do
echo -e "$user \
======================\n\
Role :\t $job\n\
ID :\t $uid\n\
SITE :\t $location\n"
done < $1
IFS=$OLDIFS
输出:
Bob Brown ======================
Role : Manager
ID : 16581
SITE : Main
Sally Seaforth ======================
Role : Director
ID : 4678
SITE : HOME
使用普通的grep
和cut
的第一个原型:
grep "${VALUE}" inputfile.csv | cut -d, -f"${INDEX}"
如果速度足够快且输出正确,则完成。
\:
)或字符串引用("foo: bar"
)。但这是解决问题的一种好而简单的方式。 - Andrey VlasovskikhCSV并不是那么简单。根据你所拥有的数据限制,你可能需要担心带引号的值(可能包含逗号和换行符)以及转义引号。
因此,如果你的数据受限制,可以轻松地使用简单的逗号分割,shell脚本可以完成这项任务。另一方面,如果你需要“正确”解析CSV,则Bash不会是我的首选。相反,我会考虑使用更高级别的脚本语言,例如Python与csv.reader。
在CSV文件中,每个字段都由逗号分隔。问题是,一个字段本身可能有嵌入的逗号:
Name,Phone
"Woo, John",425-555-1212
你真的需要一个提供稳健 CSV 支持的库包,而不是依赖逗号作为字段分隔符。我知道像 Python 这样的脚本语言有这样的支持。然而,我习惯使用 Tcl 脚本语言,因此我使用它。以下是一个简单的 Tcl 脚本,可以完成你所需的功能:
#!/usr/bin/env tclsh
package require csv
package require Tclx
# Parse the command line parameters
lassign $argv fileName columnNumber expectedValue
# Subtract 1 from columnNumber because Tcl's list index starts with a
# zero instead of a one
incr columnNumber -1
for_file line $fileName {
set columns [csv::split $line]
set columnValue [lindex $columns $columnNumber]
if {$columnValue == $expectedValue} {
puts $line
}
}
将此脚本保存为csv.tcl文件并如下调用:
$ tclsh csv.tcl filename indexNumber expectedValue
该脚本逐行读取CSV文件,并将每行存储在变量$line中,然后将每行拆分为列的列表(变量$columns)。接下来,它挑选出指定的列并将其分配给$columnValue变量。如果有匹配项,则打印出原始行。
使用 awk
:
export INDEX=2
export VALUE=bar
awk -F, '$'$INDEX' ~ /^'$VALUE'$/ {print}' inputfile.csv
编辑:根据Dennis Williamson的优秀评论,使用-v
开关定义awk变量可以使其更加清晰(和安全):
awk -F, -v index=$INDEX -v value=$VALUE '$index == value {print}' inputfile.csv
天啊...有了变量和其他东西,awk 几乎成为一种真正的编程语言...
awk
的变量传递功能,否则引号可能会让人困惑:awk -F, -v index=$INDEX -v value=$VALUE '$index == value {print}' inputfile.csv
。 - Dennis Williamson对于数据中不包含特殊字符的情况,Nate Kohl和ghostdog74提出的解决方案是好的。
如果数据字段中包含逗号或换行符,则awk可能无法正确计数字段编号,导致结果不正确。
您仍然可以使用awk,并借助我编写的一个名为csvquote的程序(可在https://github.com/dbro/csvquote上获得)来实现:
csvquote inputfile.csv | awk -F, -v index=$INDEX -v value=$VALUE '$index == value {print}' | csvquote -u
这个程序会查找引号字段内的特殊字符,并且暂时替换成不可打印的字符,以避免混淆 awk。在 awk 完成后,这些字符将被恢复。
index=1
value=2
awk -F"," -v i=$index -v v=$value '$(i)==v' file
我正在寻找一种优雅的解决方案,支持引用,并且不需要在我的VMware vMA设备上安装任何花哨的东西。结果发现这个简单的Python脚本可以实现!(我将该脚本命名为csv2tsv.py
,因为它将CSV转换为制表符分隔的值 - TSV)
#!/usr/bin/env python
import sys, csv
with sys.stdin as f:
reader = csv.reader(f)
for row in reader:
for col in row:
print col+'\t',
print
使用 cut 命令可以轻松地分割制表符分隔的值(无需指定分隔符,制表符是默认分隔符)。以下是一个示例用法/输出:
> esxcli -h $VI_HOST --formatter=csv network vswitch standard list |csv2tsv.py|cut -f12
Uplinks
vmnic4,vmnic0,
vmnic5,vmnic1,
vmnic6,vmnic2,
在我的脚本中,我实际上会逐行解析tsv输出,并使用read或cut获取我需要的字段。
cat file.csv | xsv search -s 3 foo