我正在解析一个巨大的 csv 文件,其中包含具有不同参数的行和列。但是,某些字段在包含逗号的引号内包含大量描述。如何选择排序并剪切忽略引号内逗号的列?我尝试添加 quote-comma-quote 作为分隔符,但出现错误(参数无效)或用反斜杠对引号进行转义,但也出现错误。
sort -k12 -t'","' file
或者
cut -f 12 -d '","' file
文件中的行示例:
"GFYZ01001952.1",99.606,"ASTG2327","PREDICTED: kinesin-like protein NACK1 [Elaeis guineensis]","--","centromeric protein E","Kinesin-like protein NACK1 OS=Arabidopsis thaliana GN=NACK1 PE=1 SV=1","Baculovirus polyhedron envelope protein, PEP, C terminus//Autophagy protein Apg6//Basic region leucine zipper//Protein of unknown function (DUF904)",0.005,3.2,3.5,0.00006
答案1
CSV 是一种结构化文档格式。因此,简单的文本操作工具cut
(或sort
、sed
、 或awk
,除非数据很简单)不足以安全、方便地处理 CSV 文件(因为字段可能包含嵌入的分隔符和换行符)。相反,最好使用支持 CSV 的处理工具,例如磨坊主( mlr
)。
以下 Miller 命令将该文件解析为无标头 CSV 文件,并按第 12 个字段按数字升序对其进行排序:
mlr --csv -N sort -n 12 file
如果 CSV 数据中有标题,请删除该-N
选项并使用标题名称代替12
,例如
mlr --cvs sort -n pvalue file
要提取第 12 列,
mlr --csv -N cut -f 12 file
排序和切,也只得到前10个结果,
mlr --csv -N sort -n 12 then cut -f 12 then head -n 10 file
-N
再次,如果输入中有标题,请删除并使用字段名称。
随着csvkit工具包,您可以使用它csvsort
来获得相同的结果,如下所示:
csvsort -H -c 12 file | tail -n +2
(该tail
命令删除生成的标头csvsort
),或者,使用输入中的标头,
csvsort -c pvalue file
使用以下命令提取各个字段csvcut
:
csvcut -H -c 12 file
结合csvsort
:
csvsort -H -c 12 file | csvcut -c 12 | head -n +2
或者,使用标题,
csvsort -c pvalue file | csvcut -c pvalue
没有csvhead
命令,因此必须通过其他方式将结果限制为 10 条记录,可能通过mlr --csv head -n 10
.
答案2
使用 GNU awkFPAT
可以识别字段:
$ awk -v FPAT='[^,]*|("([^"]|"")*")' '{for (i=1; i<=NF;i++) print i " <" $i ">"}' file
1 <"GFYZ01001952.1">
2 <99.606>
3 <"ASTG2327">
4 <"PREDICTED: kinesin-like protein NACK1 [Elaeis guineensis]">
5 <"--">
6 <"centromeric protein E">
7 <"Kinesin-like protein NACK1 OS=Arabidopsis thaliana GN=NACK1 PE=1 SV=1">
8 <"Baculovirus polyhedron envelope protein, PEP, C terminus//Autophagy protein Apg6//Basic region leucine zipper//Protein of unknown function (DUF904)">
9 <0.005>
10 <3.2>
11 <3.5>
12 <0.00006>
虽然您可以在 gawk 内部执行与您的sort
andcut
命令相同的操作,但如果您确实想使用这些外部命令,您可以使用 awk 将 ; 分隔的 \n 终止的记录转换为 \n 分隔的 NUL 终止的记录,然后通过管道连接到任何可以处理 NUL 终止输入的工具,然后根据需要再次转换回来,例如使用 GNU awk、剪切和排序:
$ awk -v FPAT='[^,]*|("([^"]|"")*")' -v OFS='\n' -v ORS='\0' '{$1=$1} 1' file |
cut -z -f 12 -d $'\n'
0.00006$
$ awk -v FPAT='[^,]*|("([^"]|"")*")' -v OFS='\n' -v ORS='\0' '{$1=$1} 1' file |
sort -z -k 12 -t $'\n' |
awk -v RS='\0' -v ORS='\n' -F '\n' -v OFS=';' '{$1=$1} 1'
"GFYZ01001952.1";99.606;"ASTG2327";"PREDICTED: kinesin-like protein NACK1 [Elaeis guineensis]";"--";"centromeric protein E";"Kinesin-like protein NACK1 OS=Arabidopsis thaliana GN=NACK1 PE=1 SV=1";"Baculovirus polyhedron envelope protein, PEP, C terminus//Autophagy protein Apg6//Basic region leucine zipper//Protein of unknown function (DUF904)";0.005;3.2;3.5;0.00006
看使用 awk 高效解析 csv 的最稳健方法是什么了解更多信息。