n 个文件的通讯

n 个文件的通讯

我正在寻找 n 个(即两个以上)文件的通讯功能。

man comm内容如下:

COMM(1)

NAME
       comm - compare two sorted files line by line

SYNOPSIS
       comm [OPTION]... FILE1 FILE2

DESCRIPTION
       Compare sorted files FILE1 and FILE2 line by line.

       With no options, produce three-column output.
       Column one contains lines unique to FILE1,
       column two contains lines unique to FILE2,
       and column three contains lines common to both files.

bash 中第一个非优化且不同格式的方法来说明这个想法:

user@host MINGW64 dir
$ ls
abc  ac  ad  bca  bcd

user@host MINGW64 dir
$ tail -n +1 *
==> abc <==
a
b
c

==> ac <==
a
c

==> ad <==
a
d

==> bca <==
b
c
a

==> bcd <==
b
c
d

user@host MINGW64 dir
$ bat otherdir/ncomm.sh
───────┬───────────────────────────────────────────────────────────────────────
       │ File: otherdir/ncomm.sh
───────┼───────────────────────────────────────────────────────────────────────
   1   │ #!/usr/bin/env bash
   2   │ ALLENTRIES=$(sort -u "$@")
   3   │ echo "all $*" | tr " " "\t"
   4   │
   5   │ for entry in $ALLENTRIES; do
   6   │     >&2 echo -en "${entry}\t"
   7   │     for file in "$@"; do
   8   │         foundentry=$(grep "$entry" "$file")
   9   │         echo -en "${foundentry}\t"
  10   │     done
  11   │     echo -en "\n"
  12   │ done
───────┴───────────────────────────────────────────────────────────────────────

user@host MINGW64 dir
$ time otherdir/ncomm.sh *
all     abc     ac      ad      bca     bcd
a       a       a       a       a
b       b                       b       b
c       c       c               c       c
d                       d               d

real    0m12.921s
user    0m0.579s
sys     0m4.586s

user@host MINGW64 dir
$

这将显示列标题(到 stderr),第一列“all”包含在任一文件中找到的所有条目(已排序),然后参数列表中的每个文件一列及其条目位于相应的行中。对于第一列和第一行之外的每个单元格,grep 都会被调用一次,这确实很慢。

至于 comm,此输出仅适用于像 ids 这样的短行/条目。更简洁的版本可以为第 2+ 列中找到的每个条目输出 x 或类似的值。

这应该适用于 Windows MSYS2 的 Git 和 RHEL。

如何以更高效的方式实现这一点?

答案1

meld(然而它是一个图形程序)仍然可以管理文件之间的三向比较(即n=3),但是对于任何更大的东西,实现这一点在计算上会变得越来越复杂,所以我不知道是否有一个真正的“广义” diff(或comm)工具”是完全可行的。

答案2

你可以尝试下面的方法。它具有以下特点:

  • 输出完全遵循您的示例
  • 值在处理过程中进行排序
    • => 可以跳过预排序
    • => 不保留原始订单
  • 输入文件名已排序。
  • 重复的值被清理并合并为仅出现一次(从而还修复了脚本中的一个错误,该错误显示重复值的奇怪行为)
  • 需要最新的 GNU AWK,因为它使用其内置的数组排序功能
  • 为 UNIX 行结尾量身定制,不同行结尾样式的混合会导致奇怪的效果。 (对于程序“ a”和“ a\r”是不同的东西!)

只需将代码保存到文本文件中并提供执行权限即可将其用作 shell 脚本的直接替代品。您的处理速度应该会有所加快。 (实际上是几个数量级。):)

#!/usr/bin/gawk -f
{
    all[$0]
    filenames[FILENAME]
    input[$0,FILENAME]=$0
    # if you only wanted to to mark existence
    # then uncomment the following line 
    # input[$0,FILENAME]="*"
}

END {
    PROCINFO["sorted_in"]="@ind_str_asc"
    printf "all"
    for (i in filenames) {
        printf("\t%s",i)
    }
    for (i in all) {
        printf("\n%s",i)
        for (j in filenames) {
            printf("\t%s",input[i,j])
        }
    }
    print ""
}

相关内容