使用する基本的な解決策は、最初のファイルでのみ見つかった行をプレフィックスなしで出力sed
するという事実に依存しています。comm
2番目のファイルでのみ見つかった行を単一のタブで出力します。両方のファイルで見つかった行を 2 つのタブで出力します。
また、ファイルへの書き込みはsed
のw
コマンドに依存しています。
以下を含む特定のファイル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
$
スクリプトは次のように機能します。
- 2 つのタブで始まる行を一致させ、タブを削除し、行を に書き込み、行を
file.3
削除します (スクリプトの残りの部分は無視されます)。
- 1 つのタブで始まる行を一致させ、タブを削除し、行を に書き込み、行を
file.2
削除します (スクリプトの残りの部分は無視されます)。
- タブで始まらない行を照合し、その行を に書き込み、その行を
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
(また、ファイルがメモリに収まる場合は、並べ替えられていないファイルで動作するようにすることもできます)。