是否有用于处理csv文件的强大命令行工具?


47

我使用CSV文件,有时需要从命令行快速检查行或列的内容。在许多情况下cutheadtail,和朋友将做的工作; 但是,割伤无法轻松应对以下情况

"this, is the first entry", this is the second, 34.5

在这里,第一个逗号是第一个字段的一部分,但cut -d, -f1不同意。在我自己编写解决方案之前,我想知道是否有人知道用于此工作的好工具。它至少必须能够处理上面的示例,并从CSV格式的文件返回一列。其他理想的功能包括根据第一行中给出的列名选择列的能力,对其他引用样式的支持以及对制表符分隔文件的支持。

如果您不了解这样的工具,但是对使用Bash,Perl或Python或其他常见脚本语言实现这样的程序有建议,那么我不会介意这样的建议。

Answers:


38

您可以使用Python的csv模块。

一个简单的例子:

import csv
reader = csv.reader(open("test.csv", "r"))
for row in reader:
    for col in row:
        print col

我的最终解决方案是使用python,因为我的Perl太生锈了。谢谢。
史蒂文D

2
更好的是使用Pandas。它是专门设计用于表格数据的。
2014年

38

我可能为时已晚,但是还有另一个值得一提的工具:csvkit

http://csvkit.readthedocs.org/

它具有许多命令行工具,它们可以:

  • 重新格式化CSV文件,
  • 各种格式(JSON,SQL,XLS)之间的CSV相互转换,
  • 相当于cutgrepsort等人,但CSV感知,
  • 加入不同的CSV文件,
  • 对CSV文件中的数据执行常规SQL查询。

6
一个出色地满足问题标准的出色工具(特别是它不需要跳入编程语言,并且精心制作以适合其他Unix实用程序)。
2001年

15

听起来对Perl来说是一项工作Text::CSV

perl -MText::CSV -pe '
    BEGIN {$csv = Text::CSV->new();}
    $csv->parse($_) or die;
    @fields = $csv->fields();
    print @fields[1,3];
'

请参阅文档以了解如何处理列名。分隔符和引用样式可以使用的参数进行调整new。另请参见Text::CSV::Separator分隔符猜测。


有没有可以将其压实的衬板。我喜欢perl,但
前提是

2
@ user7000,除非您的shell是(t)csh该命令,否则将在shell 提示符下正常运行。如果您希望将其中一行连接在一起,则始终可以将它们连接在一起。换行符通常就像Perl语法中的空格一样(如C
。–StéphaneChazelas 17

我猜。尽管将多于2行压缩成1条并不是我真正指的是一根班轮。我希望有一些语法糖可以隐式地完成其中的一部分(例如如何-e创建隐式循环)。
Sridhar Sarnobat

10

我发现csvfix是一个命令行工具,可以很好地完成这项工作。但是,您需要自己制作:

http://neilb.bitbucket.org/csvfix

它可以完成您期望的所有功能,排序/选择列,拆分/合并以及许多您不希望从CSV数据生成SQL插入和区分CSV数据的事情。


8

如果您想使用命令行(而不是创建整个程序来完成这项工作),则想使用rows(我正在研究的一个项目):它是表格数据的命令行界面,但是在程序中使用的Python库。使用命令行界面,您可以使用简单的命令以CSV,XLS,XLSX,HTML或库支持的任何其他表格格式漂亮地打印任何数据:

rows print myfile.csv

如果myfile.csv是这样的:

state,city,inhabitants,area
RJ,Angra dos Reis,169511,825.09
RJ,Aperibé,10213,94.64
RJ,Araruama,112008,638.02
RJ,Areal,11423,110.92
RJ,Armação dos Búzios,27560,70.28

然后,将以精美的方式打印内容,如下所示:

+-------+-------------------------------+-------------+---------+
| state |              city             | inhabitants |   area  |
+-------+-------------------------------+-------------+---------+
|    RJ |                Angra dos Reis |      169511 |  825.09 |
|    RJ |                       Aperibé |       10213 |   94.64 |
|    RJ |                      Araruama |      112008 |  638.02 |
|    RJ |                         Areal |       11423 |  110.92 |
|    RJ |            Armação dos Búzios |       27560 |   70.28 |
+-------+-------------------------------+-------------+---------+

正在安装

如果您是Python开发人员,并且已经pip安装在计算机上,则只需在virtualenv内运行或使用以下命令即可sudo

pip install rows

如果您使用的是Debian:

sudo apt-get install rows

其他酷功能

转换格式

您可以在任何受支持的格式之间进行转换:

rows convert myfile.xlsx myfile.csv

查询方式

是的,您可以将SQL转换为CSV文件:

$ rows query 'SELECT city, area FROM table1 WHERE inhabitants > 100000' myfile.csv
+----------------+--------+
|      city      |  area  |
+----------------+--------+
| Angra dos Reis | 825.09 |
|       Araruama | 638.02 |
+----------------+--------+

使用--output参数也可以将查询的输出转换为文件而不是stdout 。

作为Python库

您也可以在Python程序中:

import rows
table = rows.import_from_csv('myfile.csv')
rows.export_to_txt(table, 'myfile.txt')
# `myfile.txt` will have same content as `rows print` output

希望你喜欢它!


6

R不是我最喜欢的编程语言,但是它对像这样的事情有好处。如果您的csv文件是

***********
foo.csv
***********
 col1, col2, col3
"this, is the first entry", this is the second, 34.5
'some more', "messed up", stuff

在R解释器类型内

> x=read.csv("foo.csv", header=FALSE)

> x
                     col1                col2   col3
1 this, is the first entry  this is the second   34.5
2              'some more'           messed up  stuff
> x[1]  # first col
                      col1
1 this, is the first entry
2              'some more'
> x[1,] # first row
                      col1                col2  col3
1 this, is the first entry  this is the second  34.5

关于您的其他请求,有关“根据第一行中给出的列名选择列的能力”,请参见

> x["col1"]
                      col1
1 this, is the first entry
2              'some more'

有关“对其他引用样式的支持”,请参见quoteread.csv(和相关函数)的参数。有关“对制表符分隔文件的支持”,请参见sepread.csv 的参数(设置sep为'\ t')。

有关更多信息,请参见在线帮助。

> help(read.csv)

我对R非常熟悉,但我的目标是从Bash中轻松使用一些东西。
史蒂文D

1
@Steven:R可以很容易地从命令行运行,就像您只关心Python或Perl一样。请参阅Rscript(基本R发行版的一部分)或addon软件包littler。您可以做到#!/usr/bin/env Rscript或类似。
Faheem Mitha

是啊。我对R相当精通,但是并没有用它来创建这类实用程序。我有一些在Python中工作的东西,但是我也可以尝试在R中创建东西。
史蒂文D


4

Miller是用于处理基于名称的数据(包括CSV(带有标题))的另一个不错的工具。要提取CSV文件的第一列而不关心其名称,您可以执行以下操作

printf '"first,column",second,third\n1,2,3\n' |
  mlr --csv --implicit-csv-header --headerless-csv-output cut -f 1

米勒非常令人印象深刻。我将其与进行比较awk,但高度了解DSV。
德里克·马哈

3

或者,您可以尝试一些awk魔术。Howewer,我不是awk的好用户,无法确认它是否可以正常工作以及如何执行。


9
这是我前一段时间使用的awk CSV解析器。.似乎是经过深思熟虑的... lorance.freeshell.org/csv
Peter.O 2011年




2

cissy还将执行命令行csv处理。它是用C(小型/轻量级)编写的,其中rpm和deb软件包可用于大多数发行版。

使用示例:

echo '"this, is the first entry", this is the second, 34.5' | cissy -c 1
"this, is the first entry"

要么

echo '"this, is the first entry", this is the second, 34.5' | cissy -c 2
 this is the second

要么

echo '"this, is the first entry", this is the second, 34.5' | cissy -c 2-
 this is the second, 34.5

1

还有一个Curry库,用于以CSV格式读取/写入文件:CSV


2
您介意发布一些示例代码,例如Perl,Python和R答案吗?(特别是因为Curry不是通用的unix脚本语言。)
Gilles'SO-不再是邪恶的''

@Gilles:是的,您是对的,我应该发布一些示例代码以使答案更好。我将在一段时间内执行此操作。
imz-伊万·扎哈拉里谢夫(Ivan Zakharyaschev)2011年



1

最好的工具之一是Miller(http://johnkerl.org/miller/doc/index.html)。就像awk,sed,cut,join和对名称索引数据(例如CSV,TSV和表格JSON)进行排序。

在例子中

echo '"this, is the first entry", this is the second, 34.5' | \
mlr --icsv --implicit-csv-header cat

给你

1=this, is the first entry,2= this is the second,3= 34.5

如果您想要TSV

echo '"this, is the first entry", this is the second, 34.5' | \
mlr --c2t --implicit-csv-header cat

给你(可以删除标题)

1       2       3
this, is the first entry         this is the second      34.5

如果要第一列和第三列,请更改其顺序

echo '"this, is the first entry", this is the second, 34.5' | \
mlr --csv --implicit-csv-header --headerless-csv-output cut -o -f 3,1

给你

 34.5,"this, is the first entry"

1

如果您要在终端中使用可视/交互式工具,我会全力推荐VisiData。

在此处输入图片说明

它具有频率表(如上所示),数据透视表,融化,散点图,使用Python进行的过滤/计算等。

您可以像这样传递csv文件

vd hello.csv

有CSV特定的选项:--csv-dialect--csv-delimiter--csv-quotechar,和--csv-skipinitialspace为CSV文件微调处理。


0

awk解决方案

awk -vq='"' '
func csv2del(n) {
  for(i=n; i<=c; i++)
    {if(i%2 == 1) gsub(/,/, OFS, a[i])
    else a[i] = (q a[i] q)
    out = (out) ? out a[i] : a[i]}
  return out}
{c=split($0, a, q); out=X;
  if(a[1]) $0=csv2del(1)
  else $0=csv2del(2)}1' OFS='|' file
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.