rmb*_*rmb 23 shell text-processing csv
我想编写一个脚本,将多个 .csv 文件的内容合并到一个 .csv 文件中,即将所有其他文件的列附加到第一个文件的列中。我曾尝试使用“for”循环这样做,但无法继续。
有谁知道如何在 Linux 中做到这一点?
小智 35
实现这一目标的最简单方法是键入以下命令
cat *csv > combined.csv
Run Code Online (Sandbox Code Playgroud)
该文件将按照您提到的方式包含所有 csv 文件的内容。
Chr*_*ris 20
使用paste
paste -d ',' file1.csv file2.csv ... fileN.csv
Run Code Online (Sandbox Code Playgroud)
小智 10
awk '(NR == 1) || (FNR > 1)' *.csv > 1000Plus5years_companies_data.csv
Run Code Online (Sandbox Code Playgroud)
这是一个 perl 脚本,它读取命令行中指定的每个文件的每一行,并将其附加到数组 ( @csv
)中的元素。当没有更多输入时,它会打印出@csv
.
这些.csv
文件将按照它们在命令行中列出的顺序进行追加。
警告:此脚本假定所有输入文件的行数相同。如果任何文件的行数与其他文件的行数不同,则输出可能无法使用。
#!/usr/bin/perl
use strict;
my @csv=();
foreach (@ARGV) {
my $linenum=0;
open(F,"<",$_) or die "couldn't open $_ for read: $!\n";
while (<F>) {
chomp;
$csv[$linenum++] .= "," . $_;
};
close(F);
};
foreach (@csv) {
s/^,//; # strip leading comma from line
print $_,"\n";
};
Run Code Online (Sandbox Code Playgroud)
给定以下输入文件:
==> 1.csv <==
1,2,3,4
1,2,3,4
1,2,3,4
1,2,3,4
==> 2.csv <==
5,6,7,8
5,6,7,8
5,6,7,8
5,6,7,8
==> 3.csv <==
9,10,11,12
9,10,11,12
9,10,11,12
9,10,11,12
Run Code Online (Sandbox Code Playgroud)
它将产生以下输出:
$ ./mergecsv.pl *.csv
1,2,3,4,5,6,7,8,9,10,11,12
1,2,3,4,5,6,7,8,9,10,11,12
1,2,3,4,5,6,7,8,9,10,11,12
1,2,3,4,5,6,7,8,9,10,11,12
Run Code Online (Sandbox Code Playgroud)
好的,既然您已经阅读了这么多,是时候承认这并没有做任何没有做的事情paste -d, *.csv
。那么为什么要为 perl 烦恼呢? paste
很不灵活。如果您的数据完全正确,那么paste
您就很好 - 它非常适合这项工作,而且速度非常快。如果没有,那对你来说完全没用。
有很多方法可以改进像这样的 perl 脚本(例如,通过计算每个文件的字段数并@csv
为每个丢失的文件添加正确数量的空字段来处理不同长度的文件行。或者至少检测不同的长度并以错误退出)但如果需要更复杂的合并,这是一个合理的起点。
顺便说一句,这使用了一个非常简单的算法,并一次将所有输入文件的全部内容存储在内存 (in @csv
) 中。对于现代系统上每个高达几 MB 的文件,这并非不合理。但是,如果您正在处理巨大的 .csv 文件,则更好的算法是: