例如,如果我在一个目录中有n个文件;
a
b
c
如何将这些文件的成对组合(非定向)传递给函数?
预期输出是
a-b
a-c
b-c
这样它就可以传递给像这样的函数
fn -file1 a -file2 b
fn -file1 a -file2 c
...
这就是我现在正在尝试的。
for i in *.txt
do
for j in *.txt
do
if [ "$i" != "$j" ]
then
echo "Pairs $i and $j"
fi
done
done
输出
Pairs a.txt and b.txt
Pairs a.txt and c.txt
Pairs b.txt and a.txt
Pairs b.txt and c.txt
Pairs c.txt and a.txt
Pairs c.txt and b.txt
我仍然有重复项(ab 与 ba 相同),我想也许有更好的方法来做到这一点。
答案1
将文件名放入数组中,并通过两个循环手动运行它。
如果如果的话,您只能获得一次配对j < 我在哪里我和j分别是外循环和内循环中使用的索引。
$ touch a b c d
$ f=(*)
$ for ((i = 0; i < ${#f[@]}; i++)); do
for ((j = i + 1; j < ${#f[@]}; j++)); do
echo "${f[i]} - ${f[j]}";
done;
done
a - b
a - c
a - d
b - c
b - d
c - d
答案2
您的脚本非常接近,但您想删除重复项;即 ab 被视为 ba 的重复项。
我们可以使用不等式来处理这个问题;仅当第一个文件按字母顺序位于第二个文件之前时才显示文件名。这将确保每场比赛只有一场。
for i in *.txt
do
for j in *.txt
do
if [ "$i" \< "$j" ]
then
echo "Pairs $i and $j"
fi
done
done
这给出了输出
Pairs a.txt and b.txt
Pairs a.txt and c.txt
Pairs b.txt and c.txt
这不是一个有效的算法(它是 O(n^2)),但可能足以满足您的需求。
答案3
对于没有空格的文件名的技巧join
:
文件示例列表:
$ ls *.json | head -4
1.json
2.json
comp.json
conf.json
$ join -j9999 -o1.1,2.1 <(ls *.json | head -4) <(ls *.json | head -4) | awk '$1 != $2'
1.json 2.json
1.json comp.json
1.json conf.json
2.json 1.json
2.json comp.json
2.json conf.json
comp.json 1.json
comp.json 2.json
comp.json conf.json
conf.json 1.json
conf.json 2.json
conf.json comp.json
-j
选项指向要加入的公共字段位置;但-j9999
会引发类似的混合加入笛卡尔产品。
答案4
您可以使用 perl 的Alogithm::Combinatorics
模块来避免自己设计算法。
perl -MAlgorithm::Combinatorics=combinations -e '
if ((@files = <*.txt>) >= 2) {
for (combinations(\@files, 2)) {
system "cmd", "-file1", $_->[0], "-file2", $_->[1];
}
} else {
die "Not enough txt files in the current working directory\n";
}'
请参阅perldoc Algorithm::Combinatorics
参考资料 详细信息以及模块可以执行的其他操作。