2つのファイルを区切り文字のトリプルパイプ記号「|||」で1行ずつマージします


14

2つの言語で同じ行数を持つ2つの並列ファイルがあり、これら2つのファイルを区切り文字で1行ずつマージする予定|||です。たとえば、2つのファイルは次のとおりです。

ファイルA:

1Mo 1,1 I love you.
1Mo 1,2 I like you.
Hi 1,3 I am hungry.
Hi 1,4 I am foolish.

ファイルB:

1Mo 1,1 Ich liebe dich.
1Mo 1,2 Ich mag dich.
Hi 1,3 Ich habe Durst.
Hi 1,4 Ich bin neu.

予想される出力は次のとおりです。

1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. ||| Hi 1,4 Ich bin neu.

私はpaste次のようなコマンドを試しました:

paste -d "|||" fileA fileB

ただし、返される出力には次のようなパイプが1つしか含まれていません。

1Mo 1,1 I love you. |1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. |1Mo 1,2 Ich mag dich.

トライプパイプでラインの各ペアを分離する方法はあります|||か?


8
paste -d '|||' fileA - - fileB < /dev/null
ステファンシャゼル

5
オフトピックですが、あなたの翻訳は正しくありません;) "Ich habe Durst" =私はthisrty、 "Ich bin neu" =私は新しい...必ずしもあなたが愚かであることを意味しません。...実際にドイツ語を学習している場合に備えて
...-dave_alcarin

@StéphaneChazelasのThxを、私の出力はまだ一つだけのパイプを含むさ...
顔をしかめ

@dave_alcarinダンク・セア!
しかめ面

回答:


20

POSIX貼り付けます

:|paste -d ' ||| ' fileA - - - - fileB

pasteすべての入力ファイルの対応する行を連結します。ここには、6つのファイルfileA、、標準の4つのダミーファイル-、およびがありfileBます。

区切り文字のリストには、スペース、3つのパイプ、およびスペースがpaste循環的に使用される順序が含まれます。

6つのファイルの最初の行についてはfileA、最初のダミーファイル(何もない、no-op:演算子に感謝)と連結され、を生成しline1-fileA<space>ます。

最初のダミーファイルはパイプ、produce line1-fileA |で2番目に連結され、2 番目のダミーファイルは3番目のダミーファイル、produce line1-fileA ||、3番目のダミーファイルは4番目のダミーファイル、produce によって連結されますline1-fileA |||

そして、4番目のダミーファイルでfileB、を生成しline1-fileA ||| line1-fileBます。

これらのステップはすべての行で繰り返され、期待される結果が得られます。


の使用は:|タイピングを少なくするためであり、主に対話型シェルで使用します。スクリプトでは、次を使用する必要があります。

</dev/null paste -d ' ||| ' fileA - - - - fileB

サブシェルが生成されるのを防ぎます。


1
以下のための1 :|。巧妙な代替</dev/null
cas

4
...および+1を使用して標準入力から4つのダミーファイルをスマートに使用します- - - -が、次回は説明のために2、3行を書くこともできます:)
Hastur

THX、私はまだ1本のパイプ...と出力を得る
難色を

@hui、すべてのダッシュとスペース文字を含めて、指定されたとおりに正確にコマンドを実行しましたか?あなたのオペレーティングシステムは何ですか?
ステファンシャゼル

:|paste -d '|' fileA - - fileBスペース区切り文字なしで、より正確なバージョンを提供します。
PAL GD

7

まあ、これはsed、awk、またはgrepを使用しませんが、bashで簡単に実行できます。コマンドは次のとおりです。

(while IFS= read -r a <&3 && IFS= read -r b <&4; do echo "$a ||| $b"; done) 3<fileA 4<fileB

貼り付けの問題は、区切り文字が単一の文字であるということです。単一の文字を挿入し、sedを使用して変換することもできますが、その文字が既に入力ファイルに表示されている場合は、エラーが発生しやすくなります。


2
行にバックスラッシュ文字が含まれているか、ダッシュで始まる場合、ソリューションは機能しません。あなたはIFS=それぞれの前に使いたいread。で簡単にできますpaste。参照してください私の答えをも、そしてこの1使用を避けるべき理由を参照するにはwhile、シェルスクリプトでループを。
cuonglm

それは私のファイルで動作します。多くのThx !!!
しかめ面

5

awk(GNU)バージョン

awk '{printf ("%s ||| ", $0); getline < "fileB"; print $0 }' fileA

ではgetlineでは、コマンドawk、あなたが設定できる$0場合は、次の入力レコードから(列のすべての変数を)getline < "filename"あなたは、次を設定し$0、指定したファイルから。

getline <"file"ファイルの次のレコードから$ 0を設定します。NFを設定します。


なぜあなたの試みは期待どおりに機能しなかったのですか?man paste読むことができるから

-d, --delimiters=LIST
     reuse characters from LIST instead of TABs

ただし、各列に区切り文字を使用します

だから、コマンド
paste -d '|*|*' fileA fileB fileA fileBは次のように私に行を与えます

Hi 1,3 I am hungry.|Hi 1,3 Ich habe Durst.*Hi 1,3 I am hungry.|Hi 1,3 Ich...
Hi 1,4 I am foolish.|Hi 1,4 Ich bin neu.*Hi 1,4 I am foolish.|Hi 1,4 Ich...


sedそれはあなたの本来の目的に取得した行動にパッチを適用しているため、私は、あなたのオリジナルの試みにたとえ近くを避けるためにお勧めしていることソリューション:

 paste -d '|' fileA fileB | sed 's/|/|||/g'

避けるために、あなたは、各パターンに置き換えているので|、新しいもので|||しかし、あなたはパイプ記号(と仮定しなければならない|)、あなたのデータに存在していない他のあなたは特別な場合に対処し、副作用を回避するためのコードより複雑にする必要があり、。


Here String [ 1 ]コンストラクトを持つバリアント<<<

 paste -d ' ||| ' fileA - - - - fileB  <<< ''

-d ' ||| '(space、|、|、|、space)で5つの区切り文字を設定- - - -し、空の文字列からデータを取得する4つのダミーファイル()を設定します''


GNU Awk 4.0.1、paste(GNU coreutils)8.21およびsed(GNU sed)4.2.2でテスト済み


Thx、awkコマンドは機能します!
しかめ面

1
どういたしまして。sed(:-))およびその他のコメントを避けるための例を追加して回答を更新しました。
ハスター

4

循環区切り文字とダミーファイルの魔法とドラマを避けたい場合は、1つのファイルに区切り文字を追加してから貼り付けることができます。

paste <(sed 's/$/ |||/' filea) fileb

与える

1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. |||    Hi 1,4 Ich bin neu.

シンプルにするためにこれが好きです。「追加」ではなく「追加」を意味すると思います。このawkバージョンに対するHasturのawkの回答をご覧ください。
ワイルドカード

プロセス置換をパイプに変更する必要があります。これにより、サポートするシェルの数に制限がなくなります。
cuonglm

@Wildcardはい、先頭に追加しますが、fileaに追加するように書き直します。これにはawkがちょっとやり過ぎだと思います。
15年

@cuonglm trueですが、わかりやすくするためにパイプを避けたいと思いました。パイプがダミーファイルのように見えるようになると感じましたが、あなたは正しいです
-snth

0

この方法でもPythonで実行できます。

lines1 = [ line.rstrip() for line in open("file1") ]
lines2 = [ line.rstrip() for line in open("file2") ]
for i in xrange((len(lines1))): print lines1[i] + " ||| " + lines2[i]
... 
1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. ||| Hi 1,4 Ich bin neu.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.