合并 CSV 文件:追加而不是合并

Posted

技术标签:

【中文标题】合并 CSV 文件:追加而不是合并【英文标题】:Merging CSV files : Appending instead of merging 【发布时间】:2014-08-29 18:52:23 【问题描述】:

所以基本上我想合并几个 CSV 文件。我使用以下脚本来做到这一点:

paste -d , *.csv > final.txt

然而,这在过去对我有用,但这次它不起作用。它将数据彼此相邻而不是彼此附加。例如两个文件包含以下格式的记录

CreatedAt   ID
Mon Jul 07 20:43:47 +0000 2014  4.86249E+17
Mon Jul 07 19:58:29 +0000 2014  4.86238E+17
Mon Jul 07 19:42:33 +0000 2014  4.86234E+17

合并后给出

CreatedAt   ID CreatedAt    ID
Mon Jul 07 20:43:47 +0000 2014  4.86249E+17 Mon Jul 07 18:25:53 +0000 2014  4.86215E+17
Mon Jul 07 19:58:29 +0000 2014  4.86238E+17 Mon Jul 07 17:19:18 +0000 2014  4.86198E+17
Mon Jul 07 19:42:33 +0000 2014  4.86234E+17 Mon Jul 07 15:45:13 +0000 2014  4.86174E+17
                                            Mon Jul 07 15:34:13 +0000 2014  4.86176E+17

有谁知道这背后的原因是什么?或者我可以做些什么来强制合并以下记录?

【问题讨论】:

您的 .csv 文件之一似乎比其他 .csv 文件的行数更多。不确定您从哪里获得空间。粘贴命令使用“,”分隔条目。 你的意思是你做了cat file*.csv > final.csv。这会给你“彼此下方”的记录。祝你好运。 -d ,的目的是什么? 结果应该是怎样的?你的意思是join @ArunSangal :是的,但是计数对于加入应该不重要吗?赛勒斯 - 是的,我的意思是加入。 -d 的目的是用逗号分隔它。下面的答案也有效。 【参考方案1】:

假设所有的 csv 文件都具有相同的格式并且都以相同的标题开头, 您可以编写一个如下的小脚本来将所有文件仅附加到一个中并只在标题中添加一次

#!/bin/bash
OutFileName="X.csv"                       # Fix the output name
i=0                                       # Reset a counter
for filename in ./*.csv; do 
 if [ "$filename"  != "$OutFileName" ] ;      # Avoid recursion 
 then 
   if [[ $i -eq 0 ]] ; then 
      head -1  "$filename" >   "$OutFileName" # Copy header if it is the first file
   fi
   tail -n +2  "$filename" >>  "$OutFileName" # Append from the 2nd line each file
   i=$(( $i + 1 ))                            # Increase the counter
 fi
done

注意事项:

head -1head -n 1 命令打印文件的第一行(头部)。 tail -n +2 打印从第 2 行开始的文件尾部 (+2) Test [ ... ] 用于从输入列表中排除输出文件。 每次都会重写输出文件cat a.csv b.csv > X.csv 命令可以简单地用于将 a.csv 和 b csv 附加到单个文件中(但您复制了 2 次标头)。

paste 命令将文件粘贴到另一侧。如果文件有空格作为行,您可以获得上面报告的输出。 使用-d , 要求paste command 定义以逗号分隔的字段,,但您上面报告的文件格式并非如此。

cat 命令改为连接文件并在标准输出上打印,这意味着它一个接一个地写入文件。

请参阅man headman tail 了解单个选项的语法(某些版本允许head -1 其他而不是head -n 1)...

【讨论】:

我现在读懂了他的意思。顺便说一句,您可以将该增量放在 IF 语句中的“i”变量中,而不是在循环中。 @ArunSangal 是的。我的错误,我复制了旧版本。如果增量在if 块之外并且输出文件是列表的第一个,则输出文件中永远不会有标题。 这太完美了!感谢分享 注意到一个小问题:如果文件名包含空格,它会中断。可以通过添加一些引号来修复:"$filename". @Jonik 正确,谢谢;固定的。在拐角处偷看是很狡猾的……当您这样做时,您可能会发现另一个:最好将" 放在$OutFileName ;-)【参考方案2】:

非常感谢@wahwahwah。 我使用你的脚本制作了 nautilus-action,但它只有通过以下更改才能正常工作:

#!/bin/bash

for last; do true; done

OutFileName=$last/RESULT_`date +"%d-%m-%Y"`.csv                       # Fix the output name

i=0                                       # Reset a counter
for filename in "$last/"*".csv"; do

 if [ "$filename" != "$OutFileName" ] ;      # Avoid recursion 
 then 
   if [[ $i -eq 0 ]] ; then 
      head -1  "$filename" > "$OutFileName" # Copy header if it is the first file
   fi
   tail -n +2  "$filename" >> "$OutFileName" # Append from the 2nd line each file
   i=$(( $i + 1 ))                        # Increase the counter
 fi
done

【讨论】:

【参考方案3】:

另一种简单的答案,如 combine_csv.sh:

#!/bin/bash
 head -n 1 $1 && tail -q -n +2 $*; 

可以这样使用:

pattern="my*filenames*.csv"
combine_csv.sh $pattern > result.csv

【讨论】:

不错,& 应该是 &&

以上是关于合并 CSV 文件:追加而不是合并的主要内容,如果未能解决你的问题,请参考以下文章

追加/合并二维数组

vue.js数组追加合并与对象追加合并

Python列表合并去重和排序

为啥我的 for 循环覆盖而不是追加?

导入不断增长的 csv 文件列表(),仅在 imoprting 后追加 [重复]

php 操作数组 (合并,拆分,追加,查找,删除等)