我在特定目录中有大量 CSV 文件。所有这些都至少有 41 列且具有匹配的标题,但宽度最多可达 200 列。我只需要获取前 40 列并将它们附加到创建一个带有标题的 CSV 中。我相对较新,正在尝试遵循这个例子如何使用 bash 将所有 csv 文件的前 200 行保留在目录中?与那个结合起来将多个 .csv 文件的内容合并到单个 .csv 文件中。我试图将其限制为一行是可能的,并且我认为我需要“cut”和“cat”命令的组合。我没有成功地尝试运行这样的东西:
$ for file in *.csv do cut -d ',' -f1-40 "$file" > "$file"; done
然后
cat *csv > combined.csv
没有任何运气。
任何意见是极大的赞赏。谢谢。
答案1
不要尝试覆盖每个文件并稍后连接,而是cut
剪切所有文件并直接将结果输出到其中combined.csv
。
您需要确保combined.csv
其本身不包含在列表中,否则最终可能会导致无限循环填满您的文件系统。
(rm -f combined.csv && set ./*.csv && cut -d, -f1-40 "$@" > combined.csv)
或者(假设 GNUxargs
或兼容):
(
rm -f combined.csv &&
set ./*.csv &&
printf '%s\0' "$@" |
xargs -r0 cut -d, -f1-40 > combined.csv
)
如果文件列表csv
太大,您会得到一个“参数列表太长”错误。
如果您想删除除第一个文件之外的所有文件的标头,则需要一个循环,但即使如此,您也宁愿重定向循环的输出,而不是就地编辑每个文件并稍后连接。
(
rm -f combined.csv && set ./*.csv &&
{
cut -d, -f1-40 < "$1"
shift
for file do
tail -n+2 < "$file" | cut -d, -f1-40
done
} > combined.csv
)
在任何情况下,请注意使用tail
和cut
类似假设 csv 单元格不包含,
或换行符。为了能够处理具有任意内容的 csv,您需要使用适当的 csv 操作实用程序,例如mlr
orcsvtool
或适当的编程语言,例如perl
orpython
及其 csv 模块。
答案2
如果您的系统/限制允许,请考虑使用 CSV 专用工具。我喜欢(现在维护一个分支)GoCSV。
它是选择子命令的语法和功能非常相似切:
for file in *.csv; do
gocsv select -c 1-40 $file > processed_$file
done
然后您可以将所有经过简化、处理的 CSV“堆叠”在一起:
gocsv stack processed_*.csv > combined.csv
由于 GoCSV 能够识别 CSV 格式和标头,因此您只需几行 shell 即可获得所需的结果。
堆也有它的-文件名选项将文件名添加到特殊的分组列中,因此您可以将任何行引用回其原始文件(并使用漂亮的打印/视图MD):
gocsv stack --filenames processed_*.csv | gocsv viewmd
| foo | File |
|-----|---------------------|
| 1 | processed_file1.csv |
| 2 | processed_file1.csv |
| 3 | processed_file2.csv |
| 4 | processed_file2.csv |