重击-配对文件的每一行


10

这个问题是密切相关的这个这个问题。我有一个包含多行的文件,其中每一行都是文件的路径。现在我要配对的每一行与每一不同的线(未本身)。就我的目的而言,一对A B也等于一B A对,因此仅应产生这些组合中的一个。

files.dat 以简写形式读取,每个字母都是文件路径(绝对或相对)

a
b
c
d
e

然后我的结果应该是这样的:

a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

最好是我想用bash解决这个问题。与其他问题不同,我的文件列表很小(大约200行),因此使用循环和RAM容量不会造成任何问题。


它必须在bash中正常使用,还是只能通过bash命令行使用?其他实用程序更适合处理文本。
Jeff Schaller

@JeffSchaller可以通过bash命令行访问的东西。我有点不清楚,抱歉
Enno

这几乎变成了Code Golf:P
理查德·德·威特

3
通常,只要您需要做一些琐碎的事情,就可以在BASH上使用自己喜欢的脚本语言。它将不那么脆弱(例如,针对特殊字符或空格),并且在需要时(如果需要三个,或者将其中一些过滤掉)更容易扩展。Python或Perl应该安装在几乎所有Linux盒中,因此它们是不错的选择(除非您在像Busybox这样的嵌入式系统上工作)。
Davidmh,

Answers:


7

使用此命令:

awk '{ name[$1]++ }
    END { PROCINFO["sorted_in"] = "@ind_str_asc"
        for (v1 in name) for (v2 in name) if (v1 < v2) print v1, v2 }
        ' files.dat

PROCINFO可能是gawk扩展。如果您awk不支持它,则只需省略该PROCINFO["sorted_in"] = "@ind_str_asc"行,然后将输出通过管道传送到sort(如果您希望对输出进行排序)。

(这并没有要求要排序的输入。)


8
$ join -j 2 -o 1.1,2.1 file file | awk '!seen[$1,$2]++ && !seen[$2,$1]++'
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

假定输入文件中没有任何行包含任何空格。它还假定文件已排序

join命令创建文件中各行的全叉积。它通过在不存在的字段上将文件与其自身连接来实现此目的。非标准-j 2可以用代替-1 2 -2 2-j2除非使用GNU ,否则不能用代替join)。

awk命令将读取此结果,并且仅输出尚未看到的成对结果。


“文件已排序”是什么意思?按哪些标准排序?
恩诺

@Enno排序方式sort -b将对其进行排序。 join需要排序的输入文件。
Kusalananda

8

一个python解决方案。输入文件itertools.combinations从标准库馈入,该库生成2长度的元组,将其格式化并打印到标准输出。

python3 -c 'from itertools import combinations
with open("file") as f:
    lines = (line.rstrip() for line in f)
    lines = ("{} {}".format(x, y) for x, y in combinations(lines, 2))
    print(*lines, sep="\n")
'

6

如果已ruby安装:

$ ruby -0777 -F'\n' -lane '$F.combination(2) { |c| puts c.join(" ")}' ip.txt
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e
  • -0777 抓取整个文件(应该可以,因为在OP中提到文件大小很小)
  • -F'\n'根据换行符进行拆分,因此每行将是$F数组中的一个元素
  • $F.combination(2)一次生成组合2元素
  • { |c| puts c.join(" ")} 根据要求打印
  • 如果输入文件可以包含重复项,请使用 $F.uniq.combination(2)


一次3个元素:

$ ruby -0777 -F'\n' -lane '$F.combination(3) { |c| puts c.join(" ")}' ip.txt
a b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e


perl(非通用)

$ perl -0777 -F'\n' -lane 'for $i (0..$#F) {
                             for $j ($i+1..$#F) { 
                               print "$F[$i] $F[$j]\n" } }' ip.txt
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e


awk

$ awk '{ a[NR]=$0 }
       END{ for(i=1;i<=NR;i++)
              for(j=i+1;j<=NR;j++)
                print a[i], a[j] }' ip.txt 
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

5

这是一个纯壳壳。

test $# -gt 1 || exit
a=$1
shift
for f in "$@"
do
  echo $a $f
done
exec /bin/sh $0 "$@"

例:

~ (137) $ sh test.sh $(cat file.dat)
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e
~ (138) $ 

1
命令替换带尾随换行,所以你喜欢的东西会更好<file.dat xargs test.shtest.sh $(cat file.dat)
iruvar

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.