Docker コンテナの出力を jq にパイプしたらインデントが崩れるのを直す
docker run
や docker exec
を使って、AWS CLI 的な CLI ツールを動かす。実行結果は JSON 形式で返ってくるので、コレをパイプして jq
で整形しようと思った。
# 「get status」的なサブコマンドを実行しているイメージ
$ docker run --rm -it my-cli-container get status | jq '.'
{
"status": {
"name": "HOGE',
"created": "2020-01-01",
"info": "Running"
}
}
出力結果はイメージだが、なぜかこんな風に、どんどんインデントが増えていくような見た目になってしまった。
対策2つ
jq の GitHub Issues にドンズバの質問が挙がっていて、解決策も分かった。
まず、自分で導いた対処法は、Bash のコマンド置換 ($()
やバッククォートでコマンドを囲むアレ) を使うモノ。
$ echo "$(docker run --rm -it my-cli-container get status)" | jq '.'
こんな風にすればインデントが崩れなくなった。
GitHub Issues で見つけた対処法は、moreutils の sponge
コマンドを挟む、というモノ。
sponge
コマンドは以前も紹介したが、標準入力を一旦蓄えて、標準出力に流せるコマンド。
コレを以下のように使う。
$ docker run --rm -it my-cli-container get status | sponge | jq '.'
根本原因は -t
が余計だった
よくよく調べてみると、docker run
に -t
オプションを付けてるのが悪いんや、という指摘が。
It's natural that we can't expect correct behavior with piping against tty output.
Don't use-t
flag of docker when you use pipe from its output.
This behavior is not a bug of docker nor of jq.
The sponge from moreutils seems to solve the problem but I'm rather surprised that we can't see the tty output as well (likeecho '{"a":1}\n{"b":2}\n' >/dev/tty | jq .
).
意識せず使っていたが、-t
オプションを外すだけでキレイに行けた。
# -t オプションを外す
$ docker run --rm -i my-cli-container get status | jq '.'
# なんなら -i オプションもなくて大丈夫だった
$ docker run --rm my-cli-container get status | jq '.'
マジか…。