TL;DR
grepに色を付ける際は、--color=alwaysではなく--color=autoを使いましょう、という話です。
環境
$ zsh --version
> zsh --version
> zsh 5.7.1 (x86_64-apple-darwin17.7.0)
背景と問題
タスクを進める過程で、以下のような構造のCSVファイルから、col1またはcol2が特定の文字列である行を抽出してcol3の値が大きい順にソートする、というような処理がありました。
col1,col2,col3
a,a,10
a,a_1,20
a,a_2,5
a,a_3,10
a_1,a,25
a_1,a_1,30
a_1,a_2,20
a_1,a_3,10
例としてここでは、col1またはcol2の値がaである行を抽出する必要があったとします。
シンプルに、a,でgrepしたものをsortすれば目的の出力が得られるはずだと考えて、以下のコマンドを実行しました。
$ grep 'a,' test.csv | sort -t ',' -k 3 -rn
a,a_1,20
a,a_3,10
a,a_2,5
a_1,a,25 # numerical sortされていない
a,a,10 # 同上
あれ? なんで4、5行目が降順ソートされていないんだ?
パイプを使わずにsort単体で挙動を試したところ、col3での降順ソートは問題なく実行できる様子。
となるとgrepに原因があるのか?とアタリをつけて試行錯誤すること数十分(ツラい)。
問題のコマンドの出力をファイルにリダイレクトしてみた時、ようやく原因が分かりました。
原因
以下が、先程のコマンドの出力をテキストファイルにリダイレクトした中身です。
[01;31m[Ka,[m[Ka_1,20
[01;31m[Ka,[m[Ka_3,10
[01;31m[Ka,[m[Ka_2,5
a_1,[01;31m[Ka,[m[K25
[01;31m[Ka,[m[K[01;31m[Ka,[m[K10
一見して「ナニコレ?」と面食らってしまいましたが、調べた結果、この特殊文字は色付け用のANSI escape codeだと分かりました。
.zshrcでexport GREP_OPTIONS="--color=always"としていたので、grepの検索パターンにマッチした部分に色付け用の特殊文字が挿入されたわけです。
今回の問題は、それによって4、5行目のcol3が数値として解釈不可能な文字列になってしまい、降順数値ソートがうまく働かなかった、ということですね。
色付け設定が原因だと分かったところで、上記の行をコメントアウトして再度実行すると案の定上手くいきました。
grepの--colorオプション
「とはいえ色付けできたほうが見やすいし、何かないかな」とgrepの--colorについて調べてみると、never,auto,alwaysのいずれかが指定可能であり、それぞれ以下のような仕様だと分かりました。
-
never:色を付けない -
auto:標準出力がターミナルに繋がっている場合のみ色を付ける(パイプやリダイレクトの際は色付けしない) -
always:常に色付け(文字列を変更するので後続処理に影響を与える)
こうして見ると、基本的に**--color=alwaysに設定するメリットは薄い**と言ってしまってよさそうです。
視認性を高めるためにaliasや環境変数で指定する分には、autoでおそらく充分でしょう。
例外があるとすれば、grepの結果が長大化したときにlessに渡して閲覧する、というような状況でしょうか。
grepの--colorオプションは、実行時に渡した値が環境変数のそれに優先して使われるので、その際にだけgrep --color=alwaysとしてlessにパイプすれば、目的は果たせるかと思います。
参考にさせていただいた記事
grepコマンドに色をつける
Different results in grep results when using --color=always option
教訓
問題の根本の原因は、プログラムを書き始めた頃の自分が「とりあえずbashよりzshのが高機能らしい」「この設定にしとけば便利らしい」と、聞きかじりの知識でターミナル環境を構築してしまったところにありました。
至極当たり前のことですが、先駆者のコードや設定を使わせてもらう際は、その目的と影響範囲を正しく認識しておくのが大切ですね...
ただ、そのマインドを維持できるのもある程度の体系的な知識が有ってこそだと思いますので、今後も精進していきたいと思います。
過去の自分が何気なくコピペした.zshrcに時を超えて困らされるという、ある意味貴重な自戒の機会でした。
このささやかなハマり事例が、もし誰かのお役に立ったなら幸いです。