【问题标题】:Merging the second column of multple CSV files in git BASH在 git BASH 中合并多个 CSV 文件的第二列
【发布时间】:2017-01-21 15:56:18
【问题描述】:

我正在尝试将文件夹中多个 CSV 文件的所有第二列合并到单个 CSV 文件中(按列)。我失败了。当我尝试合并切割第一列时(通过放置-f1),但当我尝试使用第二列(-f2)时,它只会弄得一团糟。想不通为什么。这是我的代码

    for i in $FILES; 
do 
paste -d, final_table.csv <(cut -d',' -f 2 --complement "$i") > final_table_intermediate.csv; mv final_table_intermediate.csv final_table.csv ; 

done

提前致谢 埃米利亚诺

【问题讨论】:

  • 混乱在什么意义上?如果您确实想获得第二列(而不是除了第二列的所有内容),为什么要使用--complement
  • 如果您使用的是 CSV 文件,我强烈推荐使用 csvkit——它是一组 CLI 工具,可以让您轻松编写脚本。
  • 非常感谢你们! chw21 我会试试你的代码。如果我不使用补码,它将合并第 1 列和第 2 列并将其用作合并文件中的列:(
  • 您的 CSV 文件并不总是有第二列。我认为这是您的问题。

标签: bash csv command-line merge multiple-columns


【解决方案1】:

我会看看@hayden-schiff 建议的 csvkit

如果你不想走那条路,这就是我想出的。 尽管有一些警告:

更新:您的编辑表明您的输入文件并不总是有两列,我还没有找到一种方法让 cut 返回一个空字符串(但带有换行符)旧版本的工作。

所以现在我将逐行浏览 CSV,将值(或空字符串)抓取到每个输入文件的临时文件中,然后将它们全部粘贴到最后:

#!/usr/bin/env bash
FILES="infile_??.csv"
FINAL="final_table.csv"
COLUMN="3"

# Delete ${FINAL} if it exists.
[[ -f "${FINAL}" ]] && rm ${FINAL}

TMPFILES=""

for f in ${FILES}; do

    while IFS='' read -r line || [[ -n "$line" ]]; do
        val=$(cut -f ${COLUMN} -d, -s <<< $line)
        [[ -n "${val}" ]] && echo "${val}" || echo "   "
    done < "${f}" > "${f}.${COLUMN}.csv"
    TMPFILES="${TMPFILES} ${f}.${COLUMN}.csv"

done

paste -d, ${TMPFILES} > ${FINAL}
rm ${TMPFILES}

以下是我的原始版本,它假设所有文件确实至少有你想要阅读的列数:

  1. 对我的解决方案不满意,因为您一遍又一遍地打开同一个文件以同时进行读取和写入。我很想知道一种将未知数量的进程的输出作为不同的输入流传递到单个最终进程的方法。
  2. 在您的描述中,您需要第二列,但您使用--complement 选项返回除第二列之外的所有内容。这让我有点失望。我忽略了这一点并按照您的描述进行。

原来是这样:

#!/usr/bin/env bash
FILES="infile_??.csv"
FINAL="final_table.csv"
COLUMN="2"

# Delete ${FINAL} if it exists.
[[ -f "${FINAL}" ]] && rm ${FINAL}

for f in $FILES; do
    if [[ -f ${FINAL} ]]; then
        # ${FINAL} already exists from an earlier iteration

        # If you have "moreutils" installed, you can use sponge:
        # cut -d',' -f 2 ${f} | paste -d',' ${FINAL} - | sponge ${FINAL}
        # otherwise you can use "echo" in the way below:
        echo "$(cut -d',' -f ${COLUMN} ${f} | paste -d',' ${FINAL} -)" > ${FINAL}
    else
        # ${FINAL} does not yet exist, we have to create it.
        cut -d',' -f ${COLUMN} ${f} > ${FINAL}
    fi
done

更新:我的理解是它应该取每个输入文件的第二列,并将它们逐列写入输出文件,如下所示:

我的输入文件:

infile_01.txt:

111, 112, 113
121, 122, 123
131, 132, 133
141, 142, 143

infile_02.txt:

211, 212, 213
221, 222, 223
231, 232, 233
241, 242, 243

(所以每个数字是100 *(文件号)+ 10 *(行号)+(列号)。)

我的代码在我的计算机上产生以下输出:

 112, 212
 122, 222
 132, 232
 142, 242

如果这是您得到的,但不是您想要的,请告诉我输出文件与这些输入文件的外观。如果这不是你得到的,请用我的文件在你的系统上运行它并告诉我你得到了什么。

【讨论】:

  • 显然我无法让它工作:(我认为正在合并第一行中所有 CSV 文件的所有第一个单元格和第二行中的所有第二个单元格,依此类推......任何线索?
  • 我已经用我使用的输入文件和我得到的输出更新了我的答案。请将此与您想要和/或得到的进行比较。
  • 啊这太令人沮丧了!如果我选择第 1 列,您的代码可以完美运行,但如果选择第 2 列,它会再次“混乱”。顺便说一句,我的文件只有 2 列,我在更新后附加了标题,也许第 2 列结构有问题?欢呼
  • 我已经更新了我的答案。试试新版本吧。
  • 我的朋友太棒了!我认为它成功了,它运行了 4 个小时(数百个文件,每个文件有数百行)但它有效!祝福你!谢谢
猜你喜欢
  • 1970-01-01
  • 2017-09-06
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
  • 1970-01-01
  • 2020-03-16
  • 1970-01-01
相关资源
最近更新 更多