2

2 つのファイルに共通する行を見つけるための Unix コマンドの質問には、タスクを実行するためのコマンドの使用を示唆する回答があります。comm

comm -12 1.sorted.txt 2.sorted.txt

これは、2 つのファイルに共通する行を示しています ( は-1最初のファイルにのみ存在する行を-2抑制し、 は 2 番目のファイルにのみ存在する行を抑制し、両方のファイルに共通する行のみを出力として残します)。ファイル名が示すように、入力ファイルはソートされている必要があります。

その質問へのコメントで、 baporsは次のように尋ねます。

出力を異なるファイルにどのように配置しますか?

明確にするために、私は尋ねました:

あるファイルの File1 のみの行、別のファイルの File2 のみの行、および 3 番目のファイルの両方の行が必要な場合は、(ファイルの行がタブで始まらない場合)sed出力を分割するために使用できます。 3 つのファイルに。

確認されたユーザー ベイパー:

それはまさに私が求めていたものです。例を示していただけますか?

答えは比較的長く、他の質問への答えの単純さを台無しにする (多くの情報でそれをかき消す) ため、ここで個別に質問し、答えも提供しました。

4

2 に答える 2

4

使用する基本的な解決策は、最初のファイルでのみ見つかった行をプレフィックスなしで出力sedするという事実に依存しています。comm2番目のファイルでのみ見つかった行を単一のタブで出力します。両方のファイルで見つかった行を 2 つのタブで出力します。

また、ファイルへの書き込みはsedwコマンドに依存しています。

以下を含む特定のファイル1.sorted.txt:

1.line-1
1.line-2
1.line-4
1.line-6
2.line-2
3.line-5

および以下を含むファイル2.sorted.txt:

1.line-3
2.line-1
2.line-2
2.line-4
2.line-6
3.line-5

からの基本的な出力comm 1.sorted.txt 2.sorted.txtは次のとおりです。

1.line-1
1.line-2
        1.line-3
1.line-4
1.line-6
        2.line-1
                2.line-2
        2.line-4
        2.line-6
                3.line-5

script.sed以下を含むファイルがあるとします。

/^\t\t/ {
    s///
    w file.3
    d
}
/^\t/ {
    s///
    w file.2
    d
}
/^[^\t]/ {
    w file.1
    d
}

以下に示すコマンドを実行すると、次のような目的の出力が得られます。

$ comm 1.sorted.txt 2.sorted.txt | sed -f script.sed
$ cat file.1
1.line-1
1.line-2
1.line-4
1.line-6
$ cat file.2
1.line-3
2.line-1
2.line-4
2.line-6
$ cat file.3
2.line-2
3.line-5
$

スクリプトは次のように機能します。

  1. 2 つのタブで始まる行を一致させ、タブを削除し、行を に書き込み、行をfile.3削除します (スクリプトの残りの部分は無視されます)。
  2. 1 つのタブで始まる行を一致させ、タブを削除し、行を に書き込み、行をfile.2削除します (スクリプトの残りの部分は無視されます)。
  3. タブで始まらない行を照合し、その行を に書き込み、その行をfile.1削除します。

ステップ 3 の一致操作と削除操作は、何よりも対称性を重視しています。それらは省略でき ( だけを残すw file.1)、このスクリプトは同じように機能します。ただし、script3.sed対称性を維持するためのさらなる正当化については、以下を参照してください。

書かれているように、それには GNU が必要sedです。BSDはエスケープsedを認識しません。\t明らかに、\t表記の代わりに実際のタブを使用してファイルを作成することもできます。その場合、BSDsedはスクリプトで問題ありません。

コマンド ラインですべてを機能させることは可能ですが、手間がかかります (それは礼儀正しいことです)。Bash のANSI C Quotingを使用すると、次のように記述できます。

$ comm 1.sorted.txt 2.sorted.txt |
> sed -e $'/^\t\t/  { s///\n w file.3\n d\n }' \
>     -e $'/^\t/    { s///\n w file.2\n d\n }' \
>     -e $'/^[^\t]/ {        w file.1\n d\n }'
$

の 3 つの「段落」のそれぞれをscript.sed個別の-eオプションに書き込みます。wコマンドはうるさいです。スクリプトの同じ行のその後にファイル名とファイル名のみが必要であるため、\nスクリプト内のファイル名の後に を使用します。削除できるスペースはたくさんありますが、示されているレイアウトでは対称性がより明確になっています。ファイルを使用する-f script.sed方がおそらく簡単です。これは、sedスクリプトが単一引用符、二重引用符、および逆引用符で動作する必要がある場合に、Bash コマンド ラインでスクリプトを記述するのが困難になる問題を回避できるため、知っておく価値のある手法であることは間違いありません。

最後に、2 つのファイルにタブで始まる行を含めることができる場合、この手法を機能させるには、さらに強引な力が必要になります。バリアント ソリューションの 1 つは、Bash のプロセス置換を利用してファイルの行の前にプレフィックスを追加し、後処理sedスクリプトが出力ファイルに書き込む前にプレフィックスを削除します。

script3.sed(タブは最大 8 個のスペースに置き換えられます) — 今回はs///、3 番目の段落に代替が必要であることに注意してください (これdはまだオプションですが、含めることもできます):

/^              X/ {
    s///
    w file.3
    d
}
/^      X/ {
    s///
    w file.2
    d
}
/^X/ {
    s///
    w file.1
    d
}

そしてコマンドライン:

$ comm <(sed 's/^/X/' 1.sorted.txt) <(sed 's/^/X/' 2.sorted.txt) |
> sed -f script3.sed
$

同じ入力ファイルの場合、これは同じ出力を生成しますが、X各行の先頭に を追加してから削除することにより、コードはデータの並べ替え順序を変更せず、先頭のタブが存在する場合はそれを処理します。

また、Perl や Awk を使用するソリューションを簡単に作成することもできます。これらは使用する必要さえありませんcomm(また、ファイルがメモリに収まる場合は、並べ替えられていないファイルで動作するようにすることもできます)。

于 2017-09-21T05:55:11.543 に答える