我有一个csv文件和另一个文本文件(比如file1.csv和file2.txt)。文本文件有一列。现在,我想根据文本文件中的数据过滤csv文件。例如,
file1.csv ----------- 1,a,b,c 2,d,e,f 3,g,d,g file2.txt ----------- 1 3
我希望结果是 -
1,a,b,c 3,g,d,g
答案 0 :(得分:2)
尝试此命令:
awk -F, 'FNR==NR{a[$0];next};$1 in a' file2.txt file1.csv
逻辑很简单:
FOR each line in 'file2.txt' and 'file1.csv'
IF line is from 'file2.txt'
store it to array 'a'
CONTINUE
ENDIF
IF column 1 of line is in 'a'
PRINT line
ENDIF
ENDFOR
答案 1 :(得分:1)
要使用grep -f
改进解决方案,请考虑使用bash
process substitution:
grep -f <(sed 's/.*/^&,/' file2.txt) file1.csv
这在sed
中的行上使用file2.txt
将插入符号放在每行的开头,并在末尾放置一个逗号,这样当被视为正则表达式时(GNU?){{ 1}},模式只匹配行开头的确切字段值。如果您没有grep
,则可以使用:
bash
但是,当您指定sed 's/.*/^&,/' file2.txt | grep -f - file1.csv
时,并非所有版本的grep
都读取标准输入(例如,Mac OS X上的版本不会,但GNU -f -
会这样做。)< / p>
或者,您可以使用grep
命令,并使用适当的排序:
join
如果您确信文件已经排序,您可以将其简化为:
join -o 1.1,1.2,1.3,1.4 -t, <(sort file1.csv) <(sort file2.txt)
在Perl中,您可以使用:
join -o 1.1,1.2,1.3,1.4 -t, file1.csv file2.txt
也可能有其他方法可以做到这一点;例如,您可能会发现Text::CSV等模块的用途。
但是,此代码会读取每一行。如果它来自第一个文件,则会创建一个条目#!/usr/bin/env perl
use strict;
use warnings;
my $file = 0;
my %rows;
while (<>)
{
chomp;
$rows{$_}++ if ($file == 0);
if ($file == 1)
{
my($id) = split /,/;
print "$_\n" if defined $rows{$id};
}
}
continue
{
$file = 1 if eof;
}
来记录该号码。秩序和重复无所谓。在第二个(和后续)文件中,它将第一个逗号分隔的字段拆分出行,并检查是否在第一个文件中找到了该数字;如果是这样,它打印整行。 $rows{$_}++
块检测代码何时在第一个文件上达到EOF(特别是),并设置continue
。它与$file = 1;
解决方案是同构的。这有点冗长。有awk
模式(-a
模式),但由于这两个文件需要区别对待,因此让它正常工作有点棘手。
其中,我认为awk
解决方案可能是最好的,只要grep -f
不是太大(而且我不确定限制是多少 - 但可能非常大)。
对于通用CSV文件操作工具,请考虑csvfix。
答案 2 :(得分:0)
尝试以下命令:
grep -F -f file2.txt file1.csv
1,A,B,C
3,G,d,克
答案 3 :(得分:0)
对于Windows命令版:
findstr /G:file2.txt file1.csv > result.csv