BambooHero

iOSアプリ開発と株式投資をメインに色々書きます

jqでシェルの変数を使う

jqでシェルの変数を使おうとしたら意外と思った通り動かなくて苦労したので、備忘録としてまとめておきます。

フィルタでシェルの変数を使う

jq '.devices[] | select(.name == 'iPhone 12')'というjqコマンドの'...'の部分をフィルタといいます。

このフィルタのところでシェルの変数を使う例を挙げてみます。

テストデータとして以下のJSONを使います。

{
  "devices": {
    "iphone11": {
      "ios": "iOS 13.0"
    },
    "iphone12": {
      "ios": "iOS 14.0"
    }
  }
}

ここで、iphone11iosの値を取り出したいときは以下のコマンドを実行します。

$ cat test.json | jq '.devices.iphone11.ios'
"iOS 13.0"

フィルタをまるごと変数化

フィルタの内容をまるごと変数に格納し、jqコマンドで参照します。

$ filter=".devices.iphone11.ios"

$ cat test.json | jq $filter
"iOS 13.0"

フィルタの一部を変数化

フィルタの一部だけを変数に格納し、jqコマンドで参照します。

末尾に入るときはクオーテーションの外に出します。

$ filter="ios"

$ cat test.json | jq '.devices.iphone11.'$filter
"iOS 13.0"

フィルタの真ん中などで変数を使いたいときも、こんな感じでクオーテーションの外に出します。

$ name="iphone11"

$ cat test.json | jq '.devices.'$name'.ios'
"iOS 13.0"

jqコマンドにはフィルタに値を渡すオプション--argがあるのですが、シェル変数と組み合わせて使おうとすると案外うまくいきません。こういう使い方をするものではないのかな。

$ cat test.json | jq --arg arg1 $name '.devices.$arg1.ios'
jq: error: syntax error, unexpected '$', expecting FORMAT or QQSTRING_START (Unix shell quoting issues?) at <top-level>, line 1:
.devices.$arg1.ios
jq: 1 compile error

変数の値に空白やドットを含む場合

次は以下のJSONデータで考えます。キーに空白やドットが入っているケースです。

{
  "devices": {
    "iphone 11": {
      "ios": "iOS 13.0"
    },
    "iphone.12": {
      "ios": "iOS 14.0"
    }
  }
}

iphone 11iphone.12iosの値を取り出したいときはそれぞれ以下のコマンドを実行します。

空白などを含むときはフィルタ内でダブルクオーテーションでくくってあげます。

$ cat test.json | jq '.devices."iphone 11".ios'
"iOS 13.0"

$ cat test.json | jq '.devices."iphone.12".ios'
"iOS 14.0"

フィルタをまるごと変数化

以下のコマンドではうまくいきませんでした。なんかやりようはあるのかな...?

$ filter='.devices."iphone 11".ios'

$ cat test.json | jq $filter
jq: error: syntax error, unexpected $end, expecting QQSTRING_TEXT or QQSTRING_INTERP_START or QQSTRING_END (Unix shell quoting issues?) at <top-level>, line 1:
.devices."iphone
jq: 1 compile error

フィルタの一部を変数化

空白を含む場合クオーテーションが多くてややこしいですが、それぞれ以下のコマンドで実行できました。

$ name="iphone 11"

$ cat test.json | jq '.devices."'"$name"'".ios'
"iOS 13.0"

$ name="iphone.12"

$ cat test.json | jq '.devices."'$name'".ios'
"iOS 14.0"

【応用編】iOSシミュレーターのUDIDを取り出すコマンド

xcrun simctl list devices -jというコマンドを実行すると、利用可能なiOSシミュレーターを一覧化したJSONデータが出力されます。

$ xcrun simctl list devices -j
{
  "devices" : {
    "com.apple.CoreSimulator.SimRuntime.iOS-14-3" : [
      {
        "dataPath" : "\/Users\/takehiro.kaneko\/Library\/Developer\/CoreSimulator\/Devices\/7DCA532E-D95A-4B73-A389-660E85F85858\/data",
        "logPath" : "\/Users\/takehiro.kaneko\/Library\/Logs\/CoreSimulator\/7DCA532E-D95A-4B73-A389-660E85F85858",
        "udid" : "7DCA532E-D95A-4B73-A389-660E85F85858",
        "isAvailable" : true,
        "deviceTypeIdentifier" : "com.apple.CoreSimulator.SimDeviceType.iPad--7th-generation-",
        "state" : "Shutdown",
        "name" : "iPad (7th generation)"
      },
      {
...

このJSONデータから、iPhone 12iOS 14.5のシミュレーターのUDIDを取り出してみます。

$ os_version="com.apple.CoreSimulator.SimRuntime.iOS-14-5"
$ model="iPhone 12"

$ xcrun simctl list devices -j | jq -r '.devices."'$os_version'"[] | select(.name == "'"$model"'") | .udid'
97206822-70C1-404B-876E-6F34A65DCA35

まとめ

jqでシェルの変数を使う方法について説明しました。

クオーテーションの扱いがややこしいですが、わかってしまえば使うのは簡単ですね(私はこれがわかるまでなかなか時間かかってしまいました...)。

参考になれば幸いです。