文件名的成对组合

文件名的成对组合

例如,如果我在一个目录中有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参考资料 详细信息以及模块可以执行的其他操作。

相关内容