[Linux]複数ファイルの片方にしか無いリストを作る
今日もLinuxです。
Contents
シチュエーション
- 値が一列に記載されたテキスト(元リスト)がある。
- 元リストから任意の値が抽出されたテキスト(リストA)がある。
- 元リストからリストAではないリストを作りたい。
元リスト base_list
hoge fuga piyo foo bar
リストA list_a
※base_listからいくつか抜き出したリスト
hoge fuga bar
作りたいリスト list_b
※base_list – list_aのリスト
piyo foo
※順不同
結論
commを使う
$ comm -23 <(sort base_list.tsv) <(sort list_a.tsv) foo piyo
joinを使う
$ join -v 1 <(sort base_list.tsv) <(sort list_a.tsv) foo piyo
解説
comm
基本文法
$ comm file_1 file_2
file_1とfile_2を比較し、1列目にはfile_1のみ、2列目にfile_2のみ、3列目には両者に共通する項目を表示します。
option : -[数字]
-数字
とすることで、任意の列の出力を抑制できます。
これを利用して、1列目にのみ存在する項目を-23
というオプションで出力できます。
join
基本文法
$ join file_1 file_2
file_1とfile_2の共通する項目を出力するコマンドです。
オプションなしで実行したときの結果は以下になります。
$ join <(sort base_list.tsv) <(sort list_a.tsv) bar fuga hoge
option : -v
-v
オプションをつけることで、一致しない行を出力します。
なので、base_listとlist_aで一致しない、つまりbase_listにしかない行を出力します。
<(sort filename)
commもjoinも、両方のファイルが昇順ソートされている必要があります。
とはいえ毎回xxx_sort.tsvみたいなファイルを作るのも面倒です。
そこで。
$ some_cmd <(another_cmd)
の形式で、some_cmdの対象にanother_cmdの結果をもってくることができます。パイプと似たような使い方です。
ハマりポイント
commは、ファイル同士の改行コードが違うと正しく動作しません。(当たり前ですが)
VirtualBoxなどのVM環境で、ファイル共有をしてゴニョゴニョとやっているファイルを扱う場合は注意が必要です。
私はWindows <=> Linuxのコードの違いにハマって小一時間潰しました…
nkfなどのコマンドで改行コードを変換してからcommを実行しましょう。
ディスカッション
コメント一覧
まだ、コメントがありません