grep でパターンマッチする部分に色づけしたいが、うまくいかなかったので調べた際のメモ。
結論から言うと CR が問題のトリガーになっていたので、curl の出力に限ったことではなかった。
症状
curl の結果を出力しつつ Server ヘッダに注目して見たいので、Server の部分に色を付けたい。
$ curl -s -D - google.co.jp | grep --color=auto -E '^|Server:'
上記はうまくいく。
色付けを行末までにしようと、正規表現に .*
を追加する。
$ curl -s -D - google.co.jp | grep --color=auto -E '^|Server:.*'
色付けされると思いきや、見えなくなってしまった。
調査
hexdump で見てみる。
$ curl -s -D - google.co.jp | grep --color=auto -E '^|Server:.*' | hexdump -C
Server: 行は存在するが、エスケープシーケンスが見えていない。
grep --color=auto
の場合は出力先が制御端末でないと自動的に色付けを解除するようだ。
--color=always
で見てみる。
$ curl -s -D - google.co.jp | grep --color=always -E '^|Server:.*' | hexdump -C
Server: もエスケープシーケンスもあるようなので、表示する際に何かうまくいっていないようだ。
ちょっと見づらいので、strace の write(2) の方を確認する。
## strace の出力先はファイルにする
## 端末に出そうとするとエスケープシーケンスが効いてしまうので注意
$ curl -s -D - google.co.jp | strace -y -o trace.txt -e write grep --color=auto -E '^|Server:.*'
$ grep "Server:" trace.txt
write(1</dev/pts/2>, "\33[01;31m\33[KServer: gws\r\33[m\33[K\n", 30) = 30
<ESC>[K
は Erase in Line で、現在位置から行末までを消去するらしい。
Server: gws
は色づけされているが、Carriage Return で行頭に飛んでから Erase in Line で消去されて改行されるので、表示されなくなっていた。
回避策
というわけで、\r
を sed などで除去したうえで grep にかければ解決する。
$ curl -s -D - google.co.jp | sed 's/\r//g' | grep --color=auto -E '^|Server:.*'
また、ググると grep の環境変数での解決策も見つかる。
GREP_COLORS="ne"
とすることで、Erase in Line を追加しないようにしている。
$ curl -s -D - google.co.jp | GREP_COLORS="ne" grep --color=auto -E '^|Server:.*'