web-dev-qa-db-ja.com

2つのテキストファイルを交互の行数でインターリーブする方法

file1.txt:

1
2
3
4
5
6

file2.txt:

A
B
C
D
E

3:1の比率で必要な出力(file3.txt)

1
2
3
A
4
5
6
B

私が試したコマンド:

  1. sed Rfile2.txt file1.txt >file3.txt
  2. paste -d '\n' file1.txt file2.txt >file3.txt
4
puvi14

pasteの場合:

paste -d '\n' <file1.txt - - - file2.txt

ただし、サンプルのように他のファイルに行が残っている場合は、ファイルの1つが使い果たされた後も、行を出力し続けます。

awkの場合:

awk '{print}; NR % 3 == 0 {getline < "file2.txt"; print}' file1.txt

またはGNU sed相当:

sed '3~3 R file2.txt' file1.txt

今回は、file1.txtは使い果たされていますが、file2.txtが使い果たされました(そして、awkバリアントでは空の行を出力し、GNU sedバリアントでは何も出力しません)。

いずれかのファイルが使い果たされるとすぐに停止するには:

awk '{print}
     NR % 3 == 0 {
       if ((getline < "file2.txt") <= 0) exit
       print
     }' file1.txt
9
$ awk '{print} (FNR % 3)==0{getline<"file2.txt"; print}' file1.txt
1
2
3
A
4
5
6
B

使い方

  • print

    これにより、file1.txtの各行が出力されます。

  • (FNR % 3)==0{ getline <"file2.txt"; print}

    3行ごとに、file2.txtから1行を出力します。

代替案

Awkのgetlineの使用に強く反対する人もいます。その場合:

$ awk 'FNR==NR{a[NR]=$0;next} {print} (FNR % 3)==0{print a[FNR/3]}' file2.txt file1.txt
1
2
3
A
4
5
6
B

使い方

  • FNR==NR{a[NR]=$0;next}

    最初のファイルfile2.txtを読み取っている間、その行を配列aに保存してから、残りのコマンドをスキップしてnext入力行にジャンプします。

  • print

    ここに到達した場合は、2番目のファイルfile1.txtを読み取って、その行を出力します。

  • (FNR % 3)==0 {print a[FNR/3]}

    ファイルfile1.txtの行番号が3の偶数倍である場合、ファイルfile2.txtの行番号がfile1.txtの現在の行の3分の1である行を出力します。

4
John1024

Pythonの使用:

コード:

with open(sys.argv[1], 'rU') as f1, open(sys.argv[2], 'rU') as f2:
    while f1 or f2:
        for i, line in enumerate(f1):
            print line.strip()
            if i == 2:
                break
        if f2:
            try:
                print(next(f2).strip())
            except StopIteration:
                f2 = None

結果:

1
2
3
A
4
5
6
B
0
Stephen Rauch