jo について
シェルで引用符を手作業する代わりに、`jo` で JSON を組み立てる方法を扱うスキルです。値の型判定、ネスト構造、配列、ファイル入力、よく使うコマンド例を説明し、複雑な構文はマニュアルで確認するよう案内します。
主な機能
- 01シェルの値から JSON を生成
- 02JSON 値の型推定と強制指定
- 03ネストしたオブジェクトと配列の作成
- 04ファイル内容の読み込みと埋め込み
- 05既存 JSON ドキュメントの更新
- 06curl と kubectl の例
活用シーン
- 01シェル変数で API リクエスト本文を作る
- 02スクリプトでネストした JSON を生成する
- 03コマンドラインから Kubernetes リソースを変更する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ petr-korobeinikov/ skills --skill joインストール後、Claude Code で/joを入力して読み込まれたか確認します。
同梱ファイルreferences/options.md
詳細
jo
シェルスニペットで JSON を手作業で引用符付きのリテラルとして入力せずに、jo で組み立てます。
jo は JSON の引用符を内部で処理するため、
シェル変数をきれいに展開でき、
入れ子になったシングルクォートとダブルクォートを扱う必要がありません。
公式ドキュメント:
https://github.com/jpmens/jo
(README と jo.md の man ページ)。
重要な形式は、使用する前にマニュアルで確認してください。
理由
- シェル文字列内に JSON を手書きすると、引用符のエスケープが非常に複雑になります。
'{"user":"x"}'に$VARを挿入すると、シングルクォートが崩れるか、 読みにくく入力ミスもしやすい、ぎこちない'"$VAR"'の形式を使うことになります。 - インライン JSON の入力ミス(カンマの抜け、余分な引用符、末尾のカンマ)は、 パース時ではなくサーバー側で失敗するため、 長い 1 行のペイロードでは見つけにくくなります。
joは値から型を判定します。 数値、ブール値、null、ネストされたオブジェクト、配列を自動で検出します。 判定が不適切な場合(文字列のままにする必要がある数値 ID など)は、 単語ごとに-s/-n/-bで上書きできます。joは組み合わせて使えます。 シェル変数、コマンド置換、ブラケットパスの省略記法、ネストしたjo呼び出しを、 いずれも再エスケープせずに使えます。
jo による値の型判定
man ページによると、値の処理は次のとおりです。
- まず値を JSON としてパースします。
5→ 数値、true/false→ ブール値、null→ null、{...}/[...]→ 埋め込みオブジェクト/配列、 数値のように見えても有効な浮動小数点数ではない文字列 (例:3.14159.26)→ 文字列。 - JSON のパースに失敗した場合、
特殊な値のプレフィックスを確認します。
@file、%file、:file(下記の「ファイルからの読み込み」を参照)。 - **それ以外は、**リテラル文字列です。
値がない、または空の値(k=)は null になります。
リテラル文字列 true/false/null の検出を無効にするには、-B を渡します。
全体に適用される -n は、値が空のキーを削除します
(-- の後に指定する単語ごとの型変換オプション -n とは別です)。
直接置換
| 使わない | 使う |
|---|---|
'{"name":"alice"}' | "$(jo name=alice)" |
'{"name":"'"$USER"'"}' | "$(jo name="$USER")" |
'{"count":5,"active":true}' | "$(jo count=5 active=true)" |
'{"value":null}' | "$(jo value=null)"(または "$(jo value=)") |
'{"tags":["a","b","c"]}' | "$(jo tags="$(jo -a a b c)")" |
'{"point":[1,2]}' | "$(jo 'point[]=1' 'point[]=2')" |
'{"geo":{"lat":10,"lon":20}}' | "$(jo 'geo[lat]=10' 'geo[lon]=20')" |
'{"user":{"id":1,"name":"alice"}}' | "$(jo user="$(jo id=1 name=alice)")" |
'{"code":"12345"}'(文字列 ID) | "$(jo -- -s code=12345)" |
ブラケットパス形式(key[]=、key[sub]=)は1 階層のみです。
'a[b][c]=1' は [c] を黙って破棄し、{"a":{"b":1}} を生成します。
さらに深いネストには、コマンド置換を使って jo をネストしてください。
構文チートシート
値の形式
k=v— JSON としてパースし、次にプレフィックスを確認し、それ以外はリテラル文字列にします (「joによる値の型判定」を参照)。k@v— 真偽値を表す値からブール値を生成します (T/t、またはゼロ以外の数値 →true、それ以外 →false)。flag@$ENABLEDのように使うと便利です。k=@file—fileの内容を文字列値として読み込みます。k=%file—fileを読み込み、Base64 エンコードされた文字列にします。k=:file—fileを JSON としてパースし、埋め込みます。k:=fileまたはk:=-—k=:fileと同じですが、演算子として使います。-は標準入力から JSON を読み込みます。
文字列値の先頭で @、%、または : をリテラルとして使うには、\ でエスケープします。
twitter='\@jpmens'、
vimcmd='\:split'、
uri='\\%20'。
ブラケットパス(1階層)
'name[]=v1' 'name[]=v2'—name配列に追加します。'obj[k]=v'—{"obj":{"k":v}}を作成します。- ドット記法には
-d.(パス区切り文字)を組み合わせます。jo -d. geo.lat=10 geo.lon=20はjo 'geo[lat]=10' 'geo[lon]=20'と同等です。 - ブラケット形式は必ず引用符で囲んでください。
引用符のない
[/]は zsh のグロブ展開で処理されます (展開に一致するものがあれば、 bash でも同様です)。
配列
jo -a v1 v2 v3— 自動的に型変換された値の配列を作成します。jo -a -- -s 123 hello -n "five"— 配列内で単語ごとに型変換します (この例では["123","hello",4]です。 数値以外の文字列に-nを指定すると、その長さになります)。
型変換
jo -- -s k=v— 文字列に強制変換します。 数値 ID、バージョン文字列、電話番号、郵便番号に使用します。jo -- -n k=v— 数値に強制変換します (数値以外の文字列はその長さになります)。jo -- -b k=v— ブール値に強制変換します (空の場合はfalse、それ以外はtrueです)。- 単語リストの先頭の単語が
-で始まる場合は、 その前に--が必須です。 マニュアルとの一貫性を保つため、常に指定してください。
グローバルオプション
最もよく使う 2 つのオプション:
-p— 整形して出力します (本番用のペイロードでは省略してください)。-a— オブジェクトの代わりに配列を出力します。
オプションの全一覧
(-B、-D、グローバルな -n、-d sep、-f file、-e、-o、-v/-V、
および -- 以降の単語ごとの型変換の仕様)については、
references/options.md を参照してください。
イディオム
ボディ付きの curl POST:
curl -X POST https://api.example.com/v1/users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$(jo name="$NAME" email="$EMAIL" active=true)"
1 階層のネストに使うブラケット形式の省略記法
(ネストした jo のコマンド置換は不要です):
curl -X POST https://api.example.com/v1/orders \
-H "Authorization: Bearer $TOKEN" \
-d "$(jo \
'customer[id]='"$CUSTOMER_ID" \
'customer[name]='"$CUSTOMER_NAME" \
'items[]='"$SKU_A" \
'items[]='"$SKU_B")"
1 階層より深いネスト — コマンド置換で構築します (または変数に格納します):
payload=$(jo \
name="$NAME" \
address="$(jo street="$STREET" city="$CITY")" \
tags="$(jo -a admin user)")
curl -X POST -d "$payload" https://api.example.com/v1/users
kubectl のパッチ:
kubectl patch deployment web \
--type=merge \
--patch "$(jo spec="$(jo replicas=3)")"
文字列のままにする必要がある数値 ID
(そうしないと jo は "id":12345 を数値として出力します):
curl -X POST -d "$(jo -- -s id=12345 name="$NAME")" \
https://api.example.com/v1/users
既存の JSON ドキュメントを変更する:
curl -sSL https://api.example.com/v1/config \
| jo -f - updated_at="$(date -Iseconds)" version="$NEW_VERSION"
jo を使用しない場合
大きな固定 JSON ドキュメント
長い jo の呼び出しを連ねるよりも、
リテラルの JSON を含むヒアドキュメントのほうが明確で、
API ドキュメントから JSON をそのままコピーして貼り付けられます:
curl -X POST -d @- https://api.example.com/v1/config <<'JSON'
{
"feature_flags": {
"alpha": true,
"beta": false
},
"limits": {
"rps": 100,
"burst": 200
}
}
JSON
ホストで jo を使用できない場合
最小構成の CI イメージや制限されたサーバーには、
jo がない場合があります。
ヒアドキュメントを代わりに使用してください。
壊れやすいインラインの引用符付き JSON を代わりに使用してはいけません。
jo のインストール
- macOS:
brew install joまたはsudo port install jo - Debian/Ubuntu:
apt install jo - Fedora:
dnf install jo - Alpine:
apk add jo - Gentoo:
emerge jo - Arch:
pacman -S jo(extra内) - Snap:
snap install jo - Windows:
scoop install jo - Docker:
docker run --rm jpmens/jo ... - ソースから: https://github.com/jpmens/jo
jo は aqua/mise のデフォルトの短縮名レジストリには含まれていません。
mise で管理されているホストでは、パッケージマネージャー経由、
または ubi:jpmens/jo 経由でインストールしてください。
対象範囲
シェルスニペットが JSON を出力する箇所すべてに適用されます:
Bashツールの呼び出し。SKILL.md/README.md/ ドキュメント内のスニペット。scripts/配下のスクリプト。- Makefile のレシピ。
- CI 設定。
- API のスモークテスト手順。
ファイルを編集する際に、手書きのインライン JSON 文字列を見つけた場合は、
同じ編集の一環として、同等の jo 形式に置き換えてください。