Linuxを使っていると、JSON形式のファイルやWeb APIから取得したJSONデータを確認したい場面があります。しかし、JSONデータは1行にまとめられていたり、複雑な階層構造になっていたりするため、そのままでは内容を確認しにくい場合があります。
このようなときに便利なのが、jqコマンドです。jqを使用すると、JSONデータを見やすく整形したり、必要な値だけを取り出したり、条件に一致するデータを抽出したりできます。
この記事では、Linuxのjqコマンドの基本的な使い方から、よく使うオプションまで、初心者向けにわかりやすく解説します。
Linuxのjqコマンドとは?
Linuxのjqコマンドとは、JSON形式のデータを整形・抽出・加工するためのコマンドラインツールです。
JSON(JavaScript Object Notation)とは、データをキーと値の組み合わせなどで表現するデータ形式で、Web APIのレスポンスや設定ファイルなどで使用されています。例えば、次のJSONデータがあるとします。
{"name":"Taro","age":30,"email":"taro@example.com"}これをjqコマンドで整形すると、次のように表示できます。
{
"name": "Taro",
"age": 30,
"email": "taro@example.com"
}また、nameだけを取り出したり、特定の条件に一致するデータだけを抽出したりすることもできます。
jqコマンドの基本構文
jqコマンドの基本構文は次のとおりです。
jq [オプション] 'フィルター' [ファイル名]| 項目 | 説明 |
jq | JSONデータを処理するコマンド |
| オプション | 出力形式などを指定する |
| フィルター | JSONデータに対して実行する処理 |
| ファイル名 | 処理対象のJSONファイル(省略可能) |
フィルターとは、JSONデータから必要な値を取り出したり、データを加工したりするための指定です。例えば、.nameというフィルターを指定すると、nameに対応する値を取り出せます。フィルターは通常、シェルによる特殊文字の解釈を防ぐため、シングルクォーテーションで囲みます。
jqコマンドのインストール方法
UbuntuやDebian系のLinuxでは、次のコマンドを実行してインストールします。
sudo apt update
sudo apt install jqインストールが完了したら、次のコマンドでバージョンを確認します。
jq --version
# 実行結果
jq-1.8.1バージョン情報が表示されれば使用できる状態です。表示されるバージョンはインストールしたパッケージによって異なります。
jqコマンドの使い方
ここからは、jqコマンドの基本的な使い方を順番に説明します。
JSONファイルを整形して表示する
例えば、次の内容を持つuser.jsonというファイルがあるとします。
{"name":"Taro","age":30,"email":"taro@example.com"}このファイルを整形して表示する場合は、次のコマンドを実行します。
jq '.' user.json
# 実行結果
{
"name": "Taro",
"age": 30,
"email": "taro@example.com"
}jqコマンドでは、.(ドット)は入力されたJSONデータ全体を表すフィルターです。JSONのルート(最上位)を表すものと考えるとわかりやすいでしょう。
jq '.'とすることで、JSONデータ全体をインデントや改行付きで見やすく表示できます。
JSONから特定の値を取り出す
特定の値を取り出す場合は、.キー名を指定します。
例えば、.nameと指定すると、JSONのルート(最上位)にあるnameの値を取り出せます。次のコマンドを実行します。
jq '.name' user.json
# 実行結果
"Taro"ageの値を取り出す場合は、次のように指定します。
jq '.age' user.json
# 実行結果
30文字列はダブルクォーテーション付きで表示されますが、数値には付きません。
複数の値を取り出す
複数の値を取り出す場合は、フィルターをカンマ(,)で区切ります。
jq '.name, .age' user.json
# 実行結果
"Taro"
30複数の値を1つのJSONオブジェクトとして出力する場合は、次のように指定します。
jq '{name, age}' user.json
# 実行結果
{
"name": "Taro",
"age": 30
}ネストされたJSONから値を取り出す
JSONデータが階層構造になっている場合は、ドットをつなげて指定します。例えば、次の内容のprofile.jsonがあるとします。
{
"name": "Taro",
"address": {
"city": "Tokyo",
"zip": "100-0001"
}
}addressの中のcityを取り出す場合は、次のコマンドを実行します。
jq '.address.city' profile.json
# 実行結果
"Tokyo"配列から特定の要素を取り出す
JSONの配列から特定の要素を取り出す場合は、.[インデックス]を使用します。例えば、次の内容を持つusers.jsonがあるとします。
[
{"name":"Taro","age":30},
{"name":"Hanako","age":25},
{"name":"Jiro","age":35}
]配列の最初の要素を取り出す場合は、次のコマンドを実行します。
jq '.[0]' users.json
# 実行結果
{
"name": "Taro",
"age": 30
}配列のインデックスは0から始まります。最初の要素のnameだけを取り出す場合は、次のように指定します。
jq '.[0].name' users.json
# 実行結果
"Taro"配列のすべての要素を取り出す
配列のすべての要素を取り出す場合は、.[]を使用します。
jq '.[]' users.json
# 実行結果
{
"name": "Taro",
"age": 30
}
{
"name": "Hanako",
"age": 25
}
{
"name": "Jiro",
"age": 35
}すべてのユーザーのnameだけを取り出す場合は、次のように指定します。
jq '.[].name' users.json
# 実行結果
"Taro"
"Hanako"
"Jiro".[]で配列の各要素を取り出し、.nameで各要素の名前を取得しています。
一方、名前の一覧を1つのJSON配列として取得したい場合もあります。
その場合は、フィルター全体を[]で囲みます。
jq '[.[].name]' users.json
# 実行結果
[
"Taro",
"Hanako",
"Jiro"
]条件に一致するデータを抽出する
select()を使用すると、指定した条件に一致するデータだけを抽出できます。例えば、30歳以上のユーザーを抽出する場合は、次のコマンドを実行します。
jq '.[] | select(.age >= 30)' users.json
# 実行結果
{
"name": "Taro",
"age": 30
}
{
"name": "Jiro",
"age": 35
}|は、左側のフィルターの出力を右側のフィルターに渡します。まず.[]で各要素を取り出し、select(.age >= 30)で30歳以上のデータだけを抽出します。さらに名前だけを取り出す場合は、次のように指定します。
jq '.[] | select(.age >= 30) | .name' users.json
# 実行結果
"Taro"
"Jiro"なお、ここで使用している|はjqのフィルターをつなぐものです。Linuxのシェルで使用するパイプ(|)とは異なり、jq内部で左側のフィルターの出力を右側のフィルターへ渡します。
配列の要素数を取得する
lengthを使用すると、配列の要素数を取得できます。
jq 'length' users.json
# 実行結果
3JSONのキー一覧を取得する
keysを使用すると、JSONオブジェクトのキー一覧を取得できます。
jq 'keys' user.json
# 実行結果
[
"age",
"email",
"name"
]Web APIから取得したJSONデータの構造を確認する際などに便利です。
JSONの値を変更する
jqは値の変更もできます。例えば、ageを変更する場合は、次のコマンドを実行します。
jq '.age = 31' user.json
# 実行結果
{
"name": "Taro",
"age": 31,
"email": "taro@example.com"
}この操作では、元のuser.jsonは変更されません。変更した結果を保存したい場合は、次の「JSONデータをファイルに保存する」で説明する方法を使用します。
JSONデータをファイルに保存する
実行結果を保存する場合は、リダイレクト(>)を使用します。
jq '.' user.json > formatted.json整形されたJSONデータがformatted.jsonに保存されます。元のuser.jsonは変更されません。
また、以下のようにすれば、元のuser.jsonを残したまま、ageを31に変更したJSONデータがupdated.jsonに保存されます。
jq '.age = 31' user.json > updated.jsonjq '.' user.json > user.jsonのように、入力ファイルと出力ファイルに同じ名前を指定すると、シェルが元のファイルを先に空にしてしまうため、実行しないようにしましょう。
jqコマンドの主なオプション
主なオプションは次のとおりです。
| オプション | 説明 |
-r / --raw-output | 文字列をダブルクォーテーションなしで出力する |
-c / --compact-output | JSON値をコンパクトな形式で出力する |
-s / --slurp | 複数の入力JSON値を1つの配列にまとめる |
-R / --raw-input | 各入力行を文字列として読み込む |
-n / --null-input | 入力を読み込まず、nullを入力としてフィルターを1回実行する |
-S / --sort-keys | オブジェクトのキーを並べ替えて出力する |
-M / --monochrome-output | 色を付けずに出力する |
-C / --color-output | 色付きで出力する |
-e / --exit-status | 最後の出力値に応じて終了ステータスを変更する |
jq -r:ダブルクォーテーションを付けずに出力する
通常、文字列はダブルクォーテーション付きで出力されます。例えば、次のコマンドを実行します。
jq '.name' user.json
# 実行結果
"Taro"-rを指定すると、文字列をダブルクォーテーションなしで出力できます。
jq -r '.name' user.json
# 実行結果
Taroシェルスクリプトで取得した文字列を利用する場合などに便利です。
jq -c:JSONデータを1行で出力する
-cを指定すると、JSONデータをインデントや不要な空白を省いたコンパクトな形式で出力できます。通常は、1つのJSON値が1行で表示されます。
jq -c '.' user.json
# 実行結果
{"name":"Taro","age":30,"email":"taro@example.com"}複数のJSON値が入力された場合は、それぞれの値が1行ずつ出力されます。
jq -s:複数のJSONデータを配列にまとめる
例えば、次の内容を持つdata.jsonというファイルがあるとします。
{"name":"Taro"}
{"name":"Hanako"}
{"name":"Jiro"}-sを付けると、これらのJSON値を1つの配列にまとめられます。
jq -s '.' data.json
# 実行結果
[
{
"name": "Taro"
},
{
"name": "Hanako"
},
{
"name": "Jiro"
}
]元のファイルがすでに1つの配列の場合は、その配列を要素とする新しい配列が作成されます。
この例のように、1行に1つのJSONデータを記述した形式は、JSON Lines(JSONL)と呼ばれます。jqは複数のJSON値を読み込めるため、-sを指定すると、それらを1つの配列にまとめられます。
jq -R:通常のテキストを文字列として読み込む
-Rを指定すると、JSONとして解析せずに通常のテキストを文字列として読み込みます。例えば、sample.txtにred、blue、greenが1行ずつ記述されている場合は、次のコマンドを実行します。
jq -R '.' sample.txt
# 実行結果
"red"
"blue"
"green"jq -n:入力データなしでJSONを作成する
-nを指定すると、ファイルや標準入力からJSONデータを読み込まず、nullを入力としてフィルターを1回実行します。JSONデータを新しく作成する場合などに便利です。
jq -n '{"name":"Taro","age":30}'
# 実行結果
{
"name": "Taro",
"age": 30
}jq -S:JSONのキーを並べ替える
-Sを指定すると、JSONオブジェクトのキーを並べ替えて出力できます。
jq -S '.' user.json
# 実行結果
{
"age": 30,
"email": "taro@example.com",
"name": "Taro"
}jq -M:色を付けずに出力する
-Mを指定すると、色付けを無効にして出力できます。
jq -M '.name' user.json
# 実行結果
"Taro"jq -C:色付きで出力する
-Cを指定すると、色付き出力を強制できます。
jq -C '.' user.json
# 実行結果
{
"name": "Taro",
"age": 30,
"email": "taro@example.com"
}色付き出力には端末の色を制御する特殊な文字列が含まれるため、ファイル保存や他のプログラムに渡す場合は注意してください。
jq -e:出力結果に応じて終了ステータスを変更する
-eオプションを使用すると、最後に出力された値に応じて終了ステータスを変更できます。
例えば、次のコマンドを実行します。
jq -e '.age >= 30' user.json
# 実行結果
true
echo $?
# 実行結果
0echo $?は、直前に実行したコマンドの終了ステータスを確認するコマンドです。
-eを指定した場合、最後の出力結果によって終了ステータスが次のようになります。
| 最後の出力結果 | 終了ステータス |
|---|---|
trueなど(false・null以外) | 0 |
falseまたはnull | 1 |
| 有効な出力結果がない場合 | 4 |
このように、JSONデータの判定結果を終了ステータスに反映できるため、シェルスクリプトのif文などで処理を分岐させたい場合に便利です。
jqコマンドと他のコマンドを組み合わせる方法
catコマンドと組み合わせる
catコマンドで表示したJSONデータを、パイプ(|)でjqへ渡せます。
cat user.json | jq '.'
# 実行結果
{
"name": "Taro",
"age": 30,
"email": "taro@example.com"
}JSONファイルを直接指定できる場合は、jq '.' user.jsonと書く方が簡潔です。
curlコマンドと組み合わせる
curlで取得したWeb APIのJSONデータを、jqで整形することもできます。例えば、次のコマンドを実行します。
curl -s https://jsonplaceholder.typicode.com/users/1 | jq -r '.name'
# 実行結果
Leanne Grahamcurlの-sは進捗表示などを抑制するオプションです。外部のテスト用APIを使用しているため、サービスの状態によっては結果が異なる場合があります。
jqコマンドでよく使うフィルターの一覧
| フィルター | 説明 |
. | JSONデータをそのまま出力 |
.name | nameの値を取得 |
.address.city | 階層構造から値を取得 |
.[0] | 配列の最初の要素を取得 |
.[] | 配列の各要素を出力 |
.[].name | 各要素のnameを取得 |
[.[].name] | 各要素のnameを1つのJSON配列にまとめる |
.name, .age | 複数の値を出力 |
{name, age} | 指定したキーの新しいオブジェクトを作成 |
select(.age >= 30) | 条件に一致するデータを抽出 |
keys | オブジェクトのキー一覧を取得する |
length | 配列の要素数などを取得 |
.age = 31 | ageの値を31に変更する |
例えば、30歳以上のユーザーの名前をダブルクォーテーションなしで取り出す場合は、次のコマンドを実行します。
jq -r '.[] | select(.age >= 30) | .name' users.json
# 実行結果
Taro
Jirojqコマンドを使用するときの注意点
jqはJSON形式のデータを処理するコマンド
通常のテキストをJSONとして処理しようとすると、解析エラーになる場合があります。通常のテキストを読み込みたい場合は、必要に応じて-Rを使用します。
存在しないキーを指定するとnullになる
JSONオブジェクトに存在しないキーを指定すると、通常はnullが出力されます。
jq '.country' user.json
# 実行結果
null入力データの型が想定と異なる場合などは、nullではなくエラーになることもあります。
実行結果は通常、元のファイルに反映されない
jqでデータを整形・加工しても、元のJSONファイルは通常変更されません。加工した結果を保存したい場合は、別のファイルへリダイレクトします。
jq '.' user.json > formatted.json本記事のまとめ
この記事では「Linuxのjqコマンド」について、以下の内容を説明しました。
- jqはJSONデータを整形・抽出・加工するためのコマンド
- jq '.'でJSONデータを見やすく整形できる
- キー名や配列のインデックスを指定して必要な値を取り出せる
- select()で条件に一致するデータを抽出できる
- -rや-cなどのオプションで出力形式を変更できる
お読みいただきありがとうございました。