【问题标题】:Joining two csv files in bash在 bash 中加入两个 csv 文件
【发布时间】:2017-09-18 23:40:06
【问题描述】:

我必须在一列中按值join 两个文件。我需要使用 unix bash

我的第一个文件如下所示:

user_id, song_id, timestamp
00001638d6189236866af9bbf309ae6c2347ffdc,SOBBMDR12A8C13253B,1203083335
00001638d6189236866af9bbf309ae6c2347ffdc,SOBXALG12A8C13C108,984663773
00001cf0dce3fb22b0df0f3a1d9cd21e38385372,SODDNQT12A6D4F5F7E,1275071044
00001cf0dce3fb22b0df0f3a1d9cd21e38385372,SODDNQT12A6D4F5F7E,1097509573

第二个文件:

user_id, natural_key
00000b722001882066dff9d2da8a775658053ea0,6944471
00001638d6189236866af9bbf309ae6c2347ffdc,19309784
0000175652312d12576d9e6b84f600caa24c4715,10435505
00001cf0dce3fb22b0df0f3a1d9cd21e38385372,5232769

当然,这两个文件都有更多的行。我想通过第一列 (user_id) join 两个文件并得到这个结果:

natural_key, song_id, timestamp
19309784,SOBBMDR12A8C13253B,1203083335
19309784,SOBXALG12A8C13C108,984663773
5232769,SODDNQT12A6D4F5F7E,1275071044
5232769,SODDNQT12A6D4F5F7E,1097509573

我试图用joinawk 做一些事情,但无济于事。有人可以帮忙吗?

【问题讨论】:

    标签: bash join merge


    【解决方案1】:

    使用 GNU 加入、sed、排序和 bash:

    echo "natural_key, song_id, timestamp"
    join -t, <(sed '1d' file1 |sort -t, -k1,1) <(sed '1d' file2 | sort -t, -k1,1) -o 2.2,1.2,1.3
    

    输出:

    natural_key、song_id、时间戳 19309784,SOBBMDR12A8C13253B,1203083335 19309784,SOBXALG12A8C13C108,984663773 5232769,SODDNQT12A6D4F5F7E,1097509573 5232769,SODDNQT12A6D4F5F7E,1275071044

    【讨论】:

    • 您使用的是什么版本的join?这对我来说会产生错误:$ join -t, &lt;(sed '1d' file1 |sort -t, -k1,1) &lt;(sed '1d' file2 | sort -t, -k1,1) -o 2.2,1.2,1.3 usage: join [-a fileno | -v fileno ] [-e string] [-1 field] [-2 field] [-o list] [-t char] file1 file2
    • 当我写答案时,我使用了 Ubuntu 11.04 的版本。我刚刚从 GNU coreutils (Ubuntu 16.04.3) 加入 8.25 版成功地做到了。
    • 感谢您的超快速回答。我在 Unix 上,man join 只是提出了一个没有版本号但日期为 2004 年 7 月 5 日的 BSD 通用命令手册。假设我的 OSX 不是 utd!
    • @kungfujam:我已经更新了我的答案以考虑您的反馈。
    【解决方案2】:

    这是 GNU awk 中的一个(正则表达式 FS)。我将忽略您示例中的标题间距:

    $ awk 'BEGIN{FS=", ?";OFS=","}NR==FNR{a[$1]=$2;next}$1 in a{print a[$1],$2,$3}' file2 file1
    natural_key,song_id,timestamp
    19309784,SOBBMDR12A8C13253B,1203083335
    19309784,SOBXALG12A8C13C108,984663773
    5232769,SODDNQT12A6D4F5F7E,1275071044
    5232769,SODDNQT12A6D4F5F7E,1097509573
    

    解释:

    $ awk '
    BEGIN   { FS=", ?"; OFS="," }    # set the delimiters
    NR==FNR { a[$1]=$2; next }       # hash the first file in paramaters 
    $1 in a { print a[$1], $2, $3 }  # if key is found in hash, output
    ' file2 file1                    # mind the order
    

    【讨论】:

      【解决方案3】:

      使用mlr 工具:

      mlr --csvlite  join -j user_id -f f1.csv \
               then  cut -o -f ' natural_key',' song_id',' timestamp' f2.csv
      

      输出:

       natural_key, song_id, timestamp
      19309784,SOBBMDR12A8C13253B,1203083335
      19309784,SOBXALG12A8C13C108,984663773
      5232769,SODDNQT12A6D4F5F7E,1275071044
      5232769,SODDNQT12A6D4F5F7E,1097509573
      

      注意标题中的前导空格。这些都保留在这里,因为:

      1. 大部分源数据头都有前导空格,但数据没有。

      2. 如果前导空格不加引号,大多数面向 CSV 的实用程序都会失败。

      【讨论】:

      • 将您的第一列与 tech2nick 想要的第一列进行比较。
      • @Cyrus,谢谢——OP 的拼写错误和“get result like this”的措辞让我错误地推断出 OP 想要的输出示例没有意义。修改了答案,以及一些 OP 歧义。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-19
      • 2017-09-06
      • 2012-07-31
      • 2017-07-09
      • 2017-11-12
      • 1970-01-01
      相关资源
      最近更新 更多