unix - 合并具有匹配第一个字段的行

标签 unix join awk command-line bsd

几年来,我经常需要将(排序的)文本行与匹配的第一个字段相结合,但我从未找到一种优雅的(即单行 unix 命令行)方法来做到这一点。我想要的类似于 unix 的可能性 join命令,但是 join需要 2 个文件,每个键最多出现一次。我想从一个文件开始,其中一个键可能会出现多个图块。

我有一个 ruby​​ 和 perl 脚本可以执行此操作,但是无法将我的算法缩短为单行。经过多年的 Unix 使用,我仍在学习新技巧 comm , paste , uniq等,我怀疑有一种聪明的方法可以做到这一点。

还有一些相关的问题,比如join all lines that have the same first column to the same line ; Command line to match lines with matching first field (sed, awk, etc.) ;和 Combine lines with matching keys - 但这些解决方案从来没有真正给出一个干净可靠的解决方案。

这是示例输入:

apple:A fruit
apple:Type of: pie
banana:tropical fruit
cherry:small burgundy fruit
cherry:1 for me to eat
cherry:bright red

这是示例输出:
apple:A fruit;Type of: pie
banana:tropical fruit
cherry:small burgundy fruit;1 for me to eat;bright red

这是我理想的语法:
merge --inputDelimiter=":" --outputDelimiter=";" --matchfield=1 infile.txt

“比赛场”真的是可选的。它可能始终是第一个字段。分隔符的后续出现应被视为纯文本。

如果你能想到一个简短而优雅的算法,我不介意 perl、ruby、awk 单行。这应该能够处理数百万行输入。有任何想法吗?

最佳答案

使用 awk 一个类轮

awk -F: -v ORS="" 'a!=$1{a=$1; $0=RS $0} a==$1{ sub($1":",";") } 1' file

输出:
apple:A fruit;Type of: pie
banana:tropical fruit
cherry:small burgundy fruit;1 for me to eat;bright red

设置 ORS="" ;默认为 \n .
我们之所以设置ORS="" (输出记录分隔符)是因为我们不希望 awk 在每条记录的末尾在输出中包含换行符。我们想通过我们自己的逻辑以我们自己的方式处理它。我们实际上是在每条记录的开头包含换行符,该记录的第一个字段与前一个字段不同。
a!=$1 : 当变量 a (初始为空)与第一个字段不匹配 $1这是例如。 apple在第一行,然后设置 a=$1$0=RS $0$0或者干脆 whole record变成 "\n"$0 (基本上在记录的开头添加换行符)。 a!=$1当第一个字段( $1 )与前一行的 $1 不同时,将始终满足因此是根据第一个字段隔离我们的记录的标准。
a==$1 :如果匹配,则可能意味着您正在迭代属于前一个记录集的记录。在这种情况下,替换第一次出现的 $1: (注意 : )例如。 apple:; . $1":"也可以写成 $1FS哪里FS is :
如果您的文件中有数百万行,那么这种方法将是最快的,因为它不涉及任何预处理,而且我们没有使用任何其他数据结构,比如数组来存储您的键或记录。

关于unix - 合并具有匹配第一个字段的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46734615/

相关文章:

mysql - 需要在第三张 table 中加入 2 张 table 及其 FK

linux - 为什么 SED、GREP 或 AWK 无法从文本文件中删除空行?

json - 使用 jq 和 awk 拆分大型 JSON 文件

c - 写入一个或多个管道

bash - 在 bash 中可以使用纳秒级的 strftime 吗?

php - 多个连接产生不需要的结果

mysql - 我可以选择不在 RIGHT JOIN 或 JOIN 中的行吗?

linux - 使用 awk 解析 nm 命令的输出 - Linux Bash

c - C/UNIX 中两个 child 和一个 parent 之间的顺序管道

unix - docker无法从DockerFile启动服务