如何使用 Unix join 获取外连接中的所有字段?

2023-12-19

假设我有两个文件,en.csv and sp.csv,每个包含恰好两个逗号分隔的记录:

en.csv:

1,dog,red,car
3,cat,white,boat

sp.csv:

2,conejo,gris,tren
3,gato,blanco,bote

如果我执行

join -t, -a 1 -a 2 -e MISSING en.csv sp.csv

我得到的输出是:

1,dog,red,car
2,conejo,gris,tren
3,cat,white,boat,gato,blanco,bote

请注意,所有缺失的字段均已折叠。为了获得“正确的”完整外部联接,我需要指定一种格式;因此

join -t, -a 1 -a 2 -e MISSING -o 0,1.2,1.3,1.4,2.2,2.3,2.4 en.csv sp.csv

yields

1,dog,red,car,MISSING,MISSING,MISSING
2,MISSING,MISSING,MISSING,conejo,gris,tren
3,cat,white,boat,gato,blanco,bote

这种生成完整外连接的方法的一个缺点是需要显式指定最终表的格式,这在编程应用程序中可能并不容易做到(其中连接表的标识仅在运行时已知)。

GNU 的最新版本join通过支持特殊格式消除这个缺点auto。因此,有了这样的版本join上面的最后一个命令可以替换为更通用的命令

join -t, -a 1 -a 2 -e MISSING -o auto en.csv sp.csv

我怎样才能用版本达到同样的效果join不支持-o auto option?


背景和细节

我有一个 Unix shell (zsh) 脚本,旨在处理多个 CSV 平面文件,并通过以下方式实现:广泛的使用GNUjoin的“-o auto”选项。我需要修改这个脚本,以便它可以在可用的环境中工作join命令不支持-o auto选项(如 BSD 的情况join以及旧版本的 GNUjoin).

在脚本中此选项的典型用法如下:

_reccut () {
    cols="1,$1"
    shift
    in=$1
    shift
    if (( $# > 0 )); then
        join -t, -a 1 -a 2 -e 'MISSING' -o auto \
          <( cut -d, -f $cols $in | sort -t, -k1 ) \
          <( _reccut "$@" )
    else
        cut -d, -f $cols $in | sort -t, -k1
    fi
}

我举这个例子是为了说明它很难被替换-o auto使用显式格式,因为要包含在此格式中的字段直到运行时才知道。

功能_reccut上面基本上从文件中提取列,并沿着第一列连接结果表。看看如何_reccut在行动中,想象一下,除了上面提到的文件之外,我们还有以下文件

de.csv

2,Kaninchen,Grau,Zug
1,Hund,Rot,Auto

然后,例如,并排显示第 3 列en.csv,第 2 列和第 4 列sp.csv,并且 de.csv 的第 3 列将运行:

% _reccut 3 en.csv 2,4 sp.csv 3 de.csv | cut -d, 2-
red,MISSING,MISSING,Rot
MISSING,conejo,tren,Grau
white,gato,bote,MISSING

这是一个可能适用于您的数据的解决方案,也可能不适用于您的数据。它通过按行号(即记录)对齐 csv 文件中的记录来解决该问题2最终上线2, 记录3123在线号码3123等等。缺失的记录/行用以下内容填充MISSING字段,因此输入文件将被修改为如下所示:

en.csv:

1,dog,red,car
2,MISSING,MISSING,MISSING
3,cat,white,boat

de.csv:

1,Hund,Rot,Auto
2,Kaninchen,Grau,Zug
3,MISSING,MISSING,MISSING

sp.csv:

1,MISSING,MISSING,MISSING
2,conejo,gris,tren
3,gato,blanco,bote

从那里可以很容易地剪切出感兴趣的列,然后使用并排打印它们paste.

为了实现这一点,我们对输入文件进行排序first然后应用一些愚蠢的awk magic:

  • 如果一条记录出现在预期的行号上,则打印它
  • 否则,打印包含预期数量的尽可能多的行(这是基于文件中第一行的字段数,与join -o auto does) MISSING字段,直到对齐再次正确
  • 并非所有输入文件都会有相同数量的记录,因此在这一切之前会搜索最大记录数。然后,更多行MISSING打印字段直到达到最大值。

Code

reccut.sh:

#!/bin/bash

get_max_recnum()
{
    awk -F, '{ if ($1 > max) { max = $1 } } END { print max }' "$@"
}

align_by_recnum()
{
    sort -t, -k1 "$1" \
        | awk -F, -v MAXREC="$2" '
            NR==1 { for(x = 1; x < NF; x++) missing = missing ",MISSING" }
            {
                i = NR
                if (NR < $1)
                {
                    while (i < $1)
                    {
                        print i++ missing
                    }
                    NR+=i
                }
            }1
            END { for(i++; i <= MAXREC; i++) { print i missing } }
            '
}

_reccut()
{
    local infiles=()
    local args=( $@ )
    for arg; do
        infiles+=( "$2" )
        shift 2
    done
    MAXREC="$(get_max_recnum "${infiles[@]}")" __reccut "${args[@]}"
}

__reccut()
{
    local cols="$1"
    local infile="$2"
    shift 2

    if (( $# > 0 )); then
        paste -d, \
            <(align_by_recnum "${infile}" "${MAXREC}" | cut -d, -f ${cols}) \
            <(__reccut "$@")
    else
        align_by_recnum "${infile}" "${MAXREC}" | cut -d, -f ${cols}
    fi
}

_reccut "$@"

Run

$ ./reccut.sh 3 en.csv 2,4 sp.csv 3 de.csv
red,MISSING,MISSING,Rot
MISSING,conejo,tren,Grau
white,gato,bote,MISSING
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Unix join 获取外连接中的所有字段? 的相关文章

  • SQL 中的 JOIN 成本有多高?和/或,性能和标准化之间的权衡是什么?

    我发现了一个类似的线程 但它并没有真正抓住我想要问的本质 所以我创建了一个新线程 我知道规范化和性能之间存在权衡 我想知道划定这条线的最佳实践是什么 在我的特定情况下 我有一个消息传递系统 它具有三个不同的表 messages thread
  • 使用 MySQL:使用 Inner Join 更新字段的值

    我有一个主表和一个索引表 两个表共享一个称为 L Status 的公共主字段 我想根据索引表中名为 status 的引用将主表中的数据从 L Status 值 整数 更新为 L StatusLV 可读文本值 以下是我在 PHPmyAdmin
  • 基于 Unix ASCII 的命令行图表/绘图工具

    有没有好的命令行 UNIX 图表 绘图 绘图工具 我正在寻找能够在 ASCII 图表上绘制 xy 点的东西 澄清一下 我正在寻找能够以 ASCII 格式输出图形 如 ascii art 风格 的东西 这样我就可以在交互式 shell 会话中
  • 如何连接行并添加分隔符?

    命令J连接线 命令gJ连接线删除空格 是否还有连接行的命令 在行之间添加分隔符 Example Input text other text more text text 我想做的事 选择这4行 如果开始和 或 EOL 处有空格 请将其删除
  • 有哪些基于对象的 shell?

    我打算写一个面向对象的shell 基于Python 我已经有很多想法了 但在实现它之前 我想通过一些现有的 shell 来激发我的灵感 我所说的面向对象的基本意思是 参数不仅仅是字符串数组 而且是对象数组 返回值也是一个对象 不仅有 std
  • system 和 shell_exec 之间的区别

    有什么区别shell exec and systemPHP 中的方法 两者都采用单个命令行参数并在 PHP 中运行 使用其中一种比另一种更好吗 请参阅此处的解释 http chipmunkninja com Program Executio
  • mySQL MATCH 跨多个表

    我有一组 4 个表 我想对其进行搜索 每个都有全文索引 查询可以使用每个索引吗 CREATE TABLE categories id int 5 unsigned NOT NULL auto increment display order
  • 正则表达式删除块注释也删除 * 选择器

    我正在尝试使用 bash 从 css 文件中删除所有块注释 我有以下 sed 命令的正则表达式 sed r s w s w d 这可以很好地去除块注释 例如 This is a comment this is another comment
  • 仅使用扩展方法在 Linq 中进行漂亮、干净的交叉连接 [重复]

    这个问题在这里已经有答案了 可能的重复 使用扩展方法表示的嵌套 from LINQ 查询 https stackoverflow com questions 9115675 nested from linq query expressed
  • 在压缩存档内的文本文件上运行“head”,而不解压存档

    问候 我接手了之前的团队并编写了处理 csv 文件的 ETL 作业 我在 ubuntu 上结合使用 shell 脚本和 perl csv 文件很大 它们以压缩档案形式到达 解压后 很多都超过 30Gb 是的 那是 G 旧进程是在 cron
  • 安装python启动文件

    我如何安装pythonstartup文件 以便它在命令上运行 例如python myfile py 我尝试将其安装到我的 home myuserUbuntu的目录 但它说我没有足够的权限 此外 不同的地方交替说它应该全部大写或全部小写 前面
  • 如何处理文件中的特殊字符(ഀ)

    我有一个文件 当我打开它时 它看起来像这样 Notepad A B C D E 31 HB 39 Ph 49 32 FB 38 Ph 59 当我尝试从 WinScp 打开它时 它看起来如下所示 A B C D E 31 HB 39 Ph 4
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • 如何从shell脚本自动登录MySQL?

    我有一个 MySQL 服务器 其中有一个用户和密码 我想在 shell 脚本中执行一些 SQL 查询而不指定密码 如下所示 config sh MYSQL ROOT root MYSQL PASS password mysql sh sou
  • Hibernate JOIN FETCH - 对象在结果集中出现多次

    我正在使用 Spring JPA 和 Hibernate 构建 REST API 我搜索了 2 天 但没有找到任何解决方案来解决这个问题 在某些查询中 我有多个 JOIN FETCH 子句 当我执行查询时 我的结果集中多次出现父对象 实际上
  • 并行运行 shell 脚本

    我有一个 shell 脚本 打乱大型文本文件 600 万行和 6 列 根据第一列对文件进行排序 输出 1000 个文件 所以伪代码看起来像这样 file1 sh bin bash for i in seq 1 1000 do Generat
  • 检查 Git 中是否需要 pull

    如何检查远程存储库是否已更改并且需要拉取 现在我使用这个简单的脚本 git pull dry run grep q v Already up to date changed 1 但它比较重 有没有更好的办法 理想的解决方案是检查所有远程分支
  • SVN 提交后挂钩在提交后不会运行

    我的服务器上设置了 SVN 存储库 并且遇到提交后问题 我在 iMac 上使用 SmartSVN 作为客户端 我通过 SmartSVN 的 ssh svn 连接 我能够成功连接到 SVN 并对其进行更改 但从 SVN 客户端提交后 我的提交
  • 在 bash 脚本中检测鼠标点击

    我想知道如何在后台运行 bash 脚本 每当用户单击鼠标时该脚本都会执行某些操作 即运行脚本或命令或其他任何内容 即使终端关闭 我也希望它继续运行 有任何想法吗 谢谢 如果您使用的是X11 您可以尝试xdotool捕获鼠标事件 它会是这样的
  • 如何扩展路径中的波形符(~)[重复]

    这个问题在这里已经有答案了 我有一个 shell 脚本 可以从用户那里获取目录路径 但我需要检查目录是否为空 如果用户将他的主路径与 而不是绝对路径 所以我无法检查它ls echo Specify your project root dir

随机推荐