bash - 他のファイルで可能なすべての単語の組み合わせ

bash - 他のファイルで可能なすべての単語の組み合わせ

私は持っていますNファイルごとに1単語ずつ

ファイル1ファイル2ファイル3 ...
1_a 2_a 3_a
1_b 2_b 3_b
1_c 3_c

私はこれらのファイルをすべて取り出し、nワード(各ファイルごとに1つ)のすべての可能な組み合わせを生成するbashスクリプトを作成したいと思います。

私の例では、次の結果が必要です。

1_a 2_a 3_a
1_a 2_a 3_b
1_a 2_a 3_c
1_a 2_b 3_a
1_a 2_b 3_b
1_a 2_b 3_c
1_b 2_a 3_a
1_b 2_a 3_b
1_b 2_a 3_c
1_b 2_b 3_a
1_b 2_b 3_b
1_b 2_b 3_c
1_c 2_a 3_a
1_c 2_a 3_b
1_c 2_a 3_c
1_c 2_b 3_a
1_c 2_b 3_b
1_c 2_b 3_c

Pasteとawkでこれを試しましたが失敗しました。どうすればいいですか?

答え1

処理するファイルがある場合は、再帰関数を使用して自分自身を呼び出すことができます。

#!/bin/bash

process () {
    local prefix=$1
    local file=$2
    shift 2
    while read line ; do
        if (($#)) ; then                  # There are still unprocessed files.
            process "$prefix $line" "$@"
        else                              # Reading the last file.
            printf '%s\n' "$prefix $line"
        fi
    done < "$file"
}

process '' "$@"

答え2

parallel --line-buffer --keep-order echo :::: file1 :::: file2 :::: file3

https://www.gnu.org/software/parallel/parallel_tutorial.html#multiple-input-sources

答え3

あなたがそのようなことを言ったことを知っていますbash。しかし、これは次のようなものにぴったりです。python 3.3+

import sys
from contextlib import ExitStack
from itertools import product

with ExitStack() as stack:
  files = [stack.enter_context(open(f)) for f in sys.argv[1:]]
  for x in product(*files):
    x = [y.rstrip('\n') for y in x]
    print(*x)

上記のコードをというファイルに入れてcombo.py呼び出すとpython combo.py file_1 file_2 file_3 生成されます。

1_a 2_a 3_a
1_a 2_a 3_b
1_a 2_a 3_c
1_a 2_b 3_a
1_a 2_b 3_b
1_a 2_b 3_c
1_b 2_a 3_a
1_b 2_a 3_b
1_b 2_a 3_c
1_b 2_b 3_a
1_b 2_b 3_b
1_b 2_b 3_c
1_c 2_a 3_a
1_c 2_a 3_b
1_c 2_a 3_c
1_c 2_b 3_a
1_c 2_b 3_b
1_c 2_b 3_c

答え4

Bash の Brace 拡張機能は、作業に適したツールを提供します。次の簡単なケースを考えてみましょう。

$ echo {1..3}{a..c}
1a 1b 1c 2a 2b 2c 3a 3b 3c

あなたの例では、次のようなものがあります。

$ echo {1_a,1_b,1_c}{2_a,2_b}{3_a,3_b,3_c}
1_a2_a3_a 1_a2_a3_b 1_a2_a3_c 1_a2_b3_a 1_a2_b3_b 1_a2_b3_c 1_b2_a3_a 1_b2_a3_b 1_b2_a3_c 1_b2_b3_a 1_b2_b3_b 1_b2_b3_c 1_c2_a3_a 1_c2_a3_b 1_c2_a3_c 1_c2_b3_a 1_c2_b3_b 1_c2_b3_c

正しい言葉ですが、読みにくいです。よりよく説明するために、生成された出力を配列に配置してから配列を印刷できます。

$ combos=({1_a,1_b,1_c}{2_a,2_b}{3_a,3_b,3_c})
$ for i in "${combos[@]}"; do echo "$i"; done
1_a2_a3_a
1_a2_a3_b
1_a2_a3_c
1_a2_b3_a
1_a2_b3_b
1_a2_b3_c
1_b2_a3_a
1_b2_a3_b
1_b2_a3_c
1_b2_b3_a
1_b2_b3_b
1_b2_b3_c
1_c2_a3_a
1_c2_a3_b
1_c2_a3_c
1_c2_b3_a
1_c2_b3_b
1_c2_b3_c

結合された各要素間に間隔を追加して、次のように見えるようにする方法はいくつかあります。

1_a 2_a 3_a
..
..

しかし、それは別々に尋ねることができるもう一つの質問です。

関連情報