Enn*_*nno 11 shell-script text-processing
这个问题与这个和这个问题密切相关。我有一个包含多行的文件,其中每一行都是文件的路径。现在我想将每条线与每条不同的线(不是它本身)配对。此外,就我而言,一对A B
等于一B A
对,因此只应生成这些组合中的一个。
例子
files.dat
在速记符号中读起来像这样,每个字母都是一个文件路径(绝对或相对)
a
b
c
d
e
Run Code Online (Sandbox Code Playgroud)
然后我的结果应该是这样的:
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e
Run Code Online (Sandbox Code Playgroud)
最好我想在 bash 中解决这个问题。与其他问题不同,我的文件列表相当小(大约 200 行),因此使用循环和 RAM 容量没有问题。
$ 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
Run Code Online (Sandbox Code Playgroud)
这假设输入文件中没有任何行包含任何空格。它还假定文件已排序。
该join
命令创建文件中各行的完整叉积。它通过在不存在的字段上将文件与自身连接来实现此目的。非标准-j 2
可能被替换为-1 2 -2 2
(但-j2
除非你使用 GNU 否则不能被替换join
)。
该awk
命令读取此结果并仅输出尚未看到的结果对。
使用这个命令:
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
Run Code Online (Sandbox Code Playgroud)
PROCINFO
可能是一个gawk
扩展。如果您awk
不支持它,只需省略该PROCINFO["sorted_in"] = "@ind_str_asc"
行并将输出通过管道输入sort
(如果您希望输出排序)。
(这并没有要求要排序的输入。)
一个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")
'
Run Code Online (Sandbox Code Playgroud)
如果您已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
Run Code Online (Sandbox Code Playgroud)
-0777
slurp 整个文件(应该没问题,因为它在 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
Run Code Online (Sandbox Code Playgroud)
与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
Run Code Online (Sandbox Code Playgroud)
和 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
Run Code Online (Sandbox Code Playgroud)
这是一个纯外壳的。
test $# -gt 1 || exit
a=$1
shift
for f in "$@"
do
echo $a $f
done
exec /bin/sh $0 "$@"
Run Code Online (Sandbox Code Playgroud)
例子:
~ (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) $
Run Code Online (Sandbox Code Playgroud)