我正在寻找 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 ""
}