Bash-比grep更有效地处理csv文件

Bash-比grep更有效地处理csv文件,bash,grep,Bash,Grep,已更新 我有一个文件(file.txt),其中有一个单词列表: 苹果公司 香蕉 樱桃 橙色 菠萝 我有一个包含大量数据的csv文件(data.csv): 1,“美味苹果”,3,5 23,“iphone应用程序”,5,12 1,“酸葡萄”,3,5 23,“香蕉苹果冰沙”,5,12 1,“樱桃和橙子短缺”,3,5 23,“苹果iphone橙色封面”,5,12 3,“菠萝樱桃泡泡糖”,13,5 5,“菠萝最好冷冻”,22,33 我想像这样从文件中附加匹配(output.csv): 我可以使用gre

已更新

我有一个文件(
file.txt
),其中有一个单词列表:

苹果公司 香蕉 樱桃 橙色 菠萝 我有一个包含大量数据的csv文件(
data.csv
):

1,“美味苹果”,3,5
23,“iphone应用程序”,5,12
1,“酸葡萄”,3,5
23,“香蕉苹果冰沙”,5,12
1,“樱桃和橙子短缺”,3,5
23,“苹果iphone橙色封面”,5,12
3,“菠萝樱桃泡泡糖”,13,5
5,“菠萝最好冷冻”,22,33
我想像这样从文件中附加匹配(
output.csv
):

我可以使用
grep
,但为了做到这一点,我必须使用
while
循环
if
语句并处理文本文件

这样做的问题是file.txt有大约500行,data.csv有330000行。我的脚本将工作,但它可能需要几天才能完成

我想知道有没有比我的方法更有效的方法呢?

Perl来拯救我

#!/usr/bin/perl
use warnings;
use strict;

use Text::CSV_XS qw{ csv };

open my $f1, '<', 'file.txt' or die $!;
my @fruits;
chomp, push @fruits, $_ while <$f1>;
my %order;
@order{@fruits} = 0 .. $#fruits;

my $regex = join '|', sort { length $b <=> length $a } @fruits;

csv(
    in          => 'data.csv1',
    eol         => "\n",
    on_in       => sub {
        my @matches;
        push @matches, $1 while $_[1][1] =~ /\b($regex)\b/g;
        push @{ $_[1] }, join '+',
                         sort { $order{$a} <=> $order{$b} }
                         @matches;
    },
);

是否有理由要引用最后一个字段?“+”在CSV中没有特殊含义,因此不需要引号,也不需要空字段。 Text::CSV_XS不支持引用空字段或所有字段,但不支持引用所有非数字字段。 根据choroba的回答,允许最后一个字段为“apple+apple+orange”,如果需要,OP中没有明确定义,我会这样写:

使用5.14.1;
使用警告;
使用Text::CSV_XS qw(CSV);
使用Data::Peek;
chomp(my@fruits=do{local@ARGV=“file.txt”;});
我的%订单;
@订单{@fruits}=0$#果实;
my$regex=join“|”,sort{length$b length$a}@fruits;
csv(
在=>“data1.csv”中,
eol=>“\n”,
quote_empty=>1,
on_in=>sub{
推送{$\[1]},加入“+”=>
排序{$order{$a}$order{$b}
键%{{map{$\=>1}
($\[1][1]=~m/\b($regex)\b/g)};
},
);

为什么要重新考虑调用grep的循环?再次使用awk,就像在回答中一样。
awk
将是一个更好的选择。一种更有效的方法是根本不使用bash脚本,而是使用其他语言,如Python或其他任何语言。如果带引号的字段可以包含换行符、逗号或双引号,则将其包含在示例输入/输出中。还包括菠萝和葡萄柚等水果,它们的名称在您的输入/输出中包含其他水果,因此我们可以看到您希望如何处理这些水果。最后-澄清处理复数的规则,因为根本不清楚为什么
apple
apples
匹配,但是
cherry
cherries
不匹配。对于您在评论中提到的某些情况,它不起作用,但您的示例中没有包括(例如,引用字段中的逗号)所以我把它删除了,直到你发布了一个更全面和现实的例子,我们可以考虑和测试。相反,调用grep的循环是一种可怕的做法,任何人都不应该这样做。不过,您没有向我们展示该循环的内容和原因,因此我们无法说出任何有用的内容。
data.csv1
应该是脚本中的
data.csv
。另外,我在tmp.pl第22行得到一条错误消息,在数值比较()中使用未初始化值。然后在/usr/lib/x86\u 64-linux-gnu/perl/5.26/IO/Handle.pm第159行打印另一个
宽字符。
知道这些错误的原因吗?
数据。csv1
是从问题中复制的。关于“unitialized”警告:可能您在
file.txt
中有一个空行?“宽字符”意味着您过于简化了示例—实际数据包含非ASCII字符,因此您需要告诉Perl使用哪种编码。
#!/usr/bin/perl
use warnings;
use strict;

use Text::CSV_XS qw{ csv };

open my $f1, '<', 'file.txt' or die $!;
my @fruits;
chomp, push @fruits, $_ while <$f1>;
my %order;
@order{@fruits} = 0 .. $#fruits;

my $regex = join '|', sort { length $b <=> length $a } @fruits;

csv(
    in          => 'data.csv1',
    eol         => "\n",
    on_in       => sub {
        my @matches;
        push @matches, $1 while $_[1][1] =~ /\b($regex)\b/g;
        push @{ $_[1] }, join '+',
                         sort { $order{$a} <=> $order{$b} }
                         @matches;
    },
);
perl ... | sed 's/,\([^,"]*\)$/,"\1"/'