使用Awk从分隔文件中提取特定列

时间:2011-10-22 02:45:27

标签: unix csv awk

对不起,如果这太基础了。我有一个csv文件,其中列有一个标题行(v1,v2等)。我知道要提取第1列和第2列,我必须这样做:awk -F "," '{print $1 "," $2}' infile.csv > outfile.csv。但是,如果我必须提取1到10,20到25和30,33列呢?作为附录,有没有办法直接使用标题名称而不是列号来提取?

8 个答案:

答案 0 :(得分:52)

我不知道是否可以在awk中执行范围。你可以做一个for循环,但你必须添加处理来过滤掉你不想要的列。这样做可能更容易:

awk -F, '{OFS=",";print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$20,$21,$22,$23,$24,$25,$30,$33}' infile.csv > outfile.csv

需要考虑的其他事项 - 这更快更简洁:

cut -d "," -f1-10,20-25,30-33 infile.csv > outfile.csv

至于问题的第二部分,我可能会在perl中编写一个脚本,它知道如何处理标题行,从stdin或文件中解析列名,然后进行过滤。它可能是我想要用于其他事情的工具。我不确定在一个班轮上做什么,虽然我确信它可以做到。

答案 1 :(得分:13)

如@Tom所述,剪切和awk方法实际上不适用于带引号字符串的CSV。另一种方法是python模块,它提供命令行工具csvfilter。它像剪切一样工作,但正确处理CSV列引用:

csvfilter -f 1,3,5 in.csv > out.csv

如果你有python(你应该),你可以像这样安装它:

pip install csvfilter

请注意csvfilter中的列索引以0开头(与awk不同,后者以$ 1开头)。有关详情,请访问https://github.com/codeinthehole/csvfilter/

答案 2 :(得分:3)

其他语言对字段数字的范围有快捷方式,但不是awk,你必须编写代码作为你的恐惧; - )

awk -F, 'BEGIN {OFS=","} { print $1, $2, $3, $4 ..... $30, $33}' infile.csv > outfile.csv

awk中没有直接函数将字段名称用作列说明符。

我希望这会有所帮助。

答案 3 :(得分:3)

其他人已回答您之前的问题。为此:

  

作为附录,有没有办法直接使用标题名称而不是列号来提取?

我没有尝试过,但您可以将每个标头的索引存储在一个哈希中,然后使用该哈希值来获取其索引。

for(i=0;i<$NF;i++){
    hash[$i] = i;
}

然后,使用它:

j = hash["header1"];
print $j;

答案 4 :(得分:2)

您可以使用for循环来处理 $ i 的字段:

ls -l | awk '{for(i=3 ; i<8 ; i++) {printf("%s\t", $i)} print ""}'

答案 5 :(得分:1)

Tabulator是一组unix命令行工具,用于处理带有标题行的csv文件。以下是从文件test.csv:

中按名称提取列的示例
name,sex,house_nr,height,shoe_size
arthur,m,42,181,11.5
berta,f,101,163,8.5
chris,m,1333,175,10
don,m,77,185,12.5
elisa,f,204,166,7

然后tblmap -k name,height test.csv生成

name,height
arthur,181
berta,163
chris,175
don,185
elisa,166

答案 6 :(得分:0)

If Perl is an option:

perl -F, -lane 'print join ",",@F[0,1,2,3,4,5,6,7,8,9,19,20,21,22,23,24,29,32]'

-a autosplits line into @F fields array. Indices start at 0 (not 1 as in awk)
-F, field separator is ,

If your CSV file contains commas within quotes, fully fledged CSV parsers such as Perl's Text::CSV_XS are purpose-built to handle that kind of weirdness.

perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new()} if($csv->parse($_)){@f=$csv->fields();print (join ",",@f[0,1,2,3,4,5,6,7,8,9,19,20,21,22,23,24,29,32])}'

I provided more explanation within my answer here: parse csv file using gawk

答案 7 :(得分:0)

不使用awk,但我能够完成此操作的最简单方法就是使用csvtool。我还有其他用例也可以使用csvtool,如果它们出现在列数据本身内,它可以适当地处理引号或分隔符。

csvtool format '%(2)\n' input.csv
csvtool format '%(2),%(3),%(4)\n' input.csv

用列号替换2将有效地提取您要查找的列数据。