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

问题描述 投票:0回答:5

所以基本上我想合并几个 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

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

bash shell unix csv merge
5个回答
61
投票

假设所有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 -1
    head -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 head

man tail
 了解单个选项的语法(某些版本允许 
head -1
 其他替代 
head -n 1
)... 


2
投票
替代的简单答案,如combine_csv.sh:

#!/bin/bash { head -n 1 $1 && tail -q -n +2 $*; }
可以这样使用:

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

1
投票
非常感谢@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
    

1
投票
以下是我如何连接具有相同列的 CSV 文件:

(head -qn 1 *.csv | head -n 1; tail -qn +2 *.csv) >combined.csv
通过专门对任何文件调用 

head

 来节省时间:

(head -n 1 first.csv; tail -n +2 *.csv) >combined.csv
无需脚本或时髦的

awk


0
投票
尝试一下

joinem,可通过 PyPi 获得:python3 -m pip install joinem

joinem 提供了一个 CLI,可使用 polars 快速、灵活地串联表格数据。 I/O 是延迟流式传输,以便在处理大量大文件时提供良好的性能。

使用示例

通过标准输入传递输入文件,并将输出文件作为参数传递。

ls -1 path/to/*.csv | python3 -m joinem out.parquet
您可以添加 

--progress

 标志来获取进度。

更多信息

joinem 还与 parquet、JSON 和 Feather 文件类型兼容。 请参阅项目的 README 了解更多使用示例和完整的命令行界面 API 列表。

披露:我是joinem的库作者。

© www.soinside.com 2019 - 2024. All rights reserved.