jqコマンドを使って改行エスケープ文字列を含むワンライナーを改行させて出力する

Bash,JavaScript

最近はデータファイルやロギングデータとして JSON フォーマットが一般化しました。
僕のまだ若い頃にはタブ区切りカンマ区切りといたほうが後が一般的だったのが懐かしいです。(こんな発言していると老害なんて言われてしまいますね。)

さてそんな JSON フォーマット。スキーマレスでさっとアプリケーションを作る際のデータフォーマットとして非常に便利。
しかし、複数行にまたがる文字列を格納する際は改行を “¥n” (Macだと "\n" ) のような改行エスケープシーケンス使って変換し清掃内に格納します。当然のことながら人間には非常に読みにくいです。

チームメンバから jq コマンドを使って JSON のデータをパースして確認する際に、見やすくする方法がないか質問されました。

お答えしたいと思います。

特にオプションを指定せずに jq コマンドを使った場合

まずはサンプルの JSON データを用意します

$ cat <<EOF > test.json
{
  "subject": "sample json data",
  "body": "# Greetings\n\n## English\n\nhello world!\n\n## Japanese\n\nこんにちわ世界!"
}
EOF

$ cat test.json
{
  "subject": "sample json data",
  "body": "# Greetings\n\n## English\n\nhello world!\n\n## Japanese\n\nこんにちわ世界!"
}

次に、jqコマンドを使って作成した test.json ファイルの subject、body 属性を出力してみます。

$ cat test.json | jq .subject
"sample json data"

$ cat test.json | jq .body
"# Greetings\n\n## English\n\nhello world!\n\n## Japanese\n\nこんにちわ世界!"

subject 属性はもともと改行が含まれていないため見やすいです。
打って変わって body 属性は改行が複数含まれているため元々どんなテキストだったのかはぱっとみ分かりません。

-r オプションを付与して jqコマンドを使った場合

そこでjqコマンドで提供されている -r オプションを使用します。
先ほどのコマンドを -r オプション付きで実行してみます。

$ cat test.json | jq -r .subject
sample json data

$ cat test.json | jq -r .body
# Greetings

## English

hello world!

## Japanese

こんにちわ世界!

元々は Markdown フォーマットだったということが一目で分かります。

ダブルクォートを出力させない用途で利用することが多いですが、エスケープシーケンスも出力されるようになります。

当然 "\n" 以外のエスケープシーケンスも出力できる

当然、 "\n" 以外のエスケープシーケンスを出力する事もできます。

例えば、 "\b" を含んだ文字列を出力してみましょう。

$ cat <<EOF > test.json
> {
>   "text": "aaa\bccc"
> }
> EOF

これを出力させてみます。

# -rオプションなし
$ cat test.json | jq .text
"aaa\bccc"

# -rオプションあり
$ cat test.json | jq -r .text
aaccc

-r オプションつきで出力すると、 "a" の文字が1つだけ削られていることがわかります。 "\b" は1文字分出力キャレットを戻す、というエスケープシーケンスです。

ひとこと

CUI でクラウドのマネージドサービスを操作する際、 jq コマンドの使い方を覚えておくと非常に便利です。
ところが、比較的最近(と言っても僕も出会ってから 8 年ぐらい立っていますが)になって登場したコマンドということもあり、昔から使っている UNIX コマンドに比べるとオプションを覚えていないのが難点です。

Bash,JavaScript