GNU/Linux中两个文件(作为行集)的笛卡尔积

P S*_*ved 15 linux shell

我如何使用shell单行和常用GNU工具来连接两个文件中的行,如笛卡尔积?什么是最简洁,美丽和"linuxy"的方式?

例如,如果我有两个文件:

$ cat file1
a
b
$ cat file2
c
d
e
Run Code Online (Sandbox Code Playgroud)

结果应该是

a, c
a, d
a, e
b, c
b, d
b, e
Run Code Online (Sandbox Code Playgroud)

pix*_*eat 14

这是shell脚本来做到这一点

while read a; do while read b; do echo "$a, $b"; done < file2; done < file1
Run Code Online (Sandbox Code Playgroud)

虽然那会很慢.我无法想到任何预编译逻辑来实现这一目标.速度的下一步是在awk/perl中执行上述操作.

awk 'NR==FNR { a[$0]; next } { for (i in a) print i",", $0 }' file1 file2
Run Code Online (Sandbox Code Playgroud)

嗯,这个使用预编译逻辑的hacky解决方案怎么样?

paste -d, <(sed -n "$(yes 'p;' | head -n $(wc -l < file2))" file1) \
          <(cat $(yes 'file2' | head -n $(wc -l < file1)))
Run Code Online (Sandbox Code Playgroud)

  • @Telemachus,顺序无关紧要:如果我说"笛卡尔积",我真的意思是*. (3认同)
  • @Pixelbeat:你的第一个版本需要颠倒`file1`和`file2`的顺序.(也就是说,它应该是`done <file2; done <file 1`来获得所需的结果. (2认同)

Jam*_*own 7

不会有逗号分隔,只能使用join:

$ join -j 2 file1 file2
 a c
 a d
 a e
 b c
 b d
 b e
Run Code Online (Sandbox Code Playgroud)


Jon*_*ler 6

在shell中执行它的机械方法,不是使用Perl或Python,是:

while read line1
do
    while read line2
    do echo "$line1, $line2"
    done < file2
done < file1
Run Code Online (Sandbox Code Playgroud)

join命令有时可用于这些操作 - 但是,我不清楚它可以将笛卡尔积作为退化情况.

从双循环向上一步将是:

while read line1
do
    sed "s/^/$line1, /" file2
done < file1
Run Code Online (Sandbox Code Playgroud)


Bri*_*man 6

我不会假装这很漂亮,但......

join -t, -j 9999 -o 2.1,1.1 /tmp/file1 /tmp/file2
Run Code Online (Sandbox Code Playgroud)

(感谢下面的Iwan Aucamp)

- join(GNU coreutils)8.4


Pau*_*ce. 5

编辑

DVK的尝试启发了我这样做eval

script='1{x;d};${H;x;s/\n/\,/g;p;q};H'
eval "echo {$(sed -n $script file1)}\,\ {$(sed -n $script file2)}$'\n'"|sed 's/^ //'
Run Code Online (Sandbox Code Playgroud)

或者更简单的sed脚本:

script=':a;N;${s/\n/,/g;b};ba'
Run Code Online (Sandbox Code Playgroud)

您可以在没有-n开关的情况下使用。

这使:

a, c
a, d
a, e
b, c
b, d
b, e
Run Code Online (Sandbox Code Playgroud)

原答案:

在 Bash 中,您可以做到这一点。它不从文件中读取,但这是一个巧妙的技巧:

$ echo {a,b}\,\ {c,d,e}$'\n'
a, c
 a, d
 a, e
 b, c
 b, d
 b, e
Run Code Online (Sandbox Code Playgroud)

更简单:

$ echo {a,b}{c,d,e}
ac ad ae bc bd be
Run Code Online (Sandbox Code Playgroud)