概要
この記事は、AWS CloudShellでjqのjoinを使用する際に発生するエラーの原因と解決方法を説明しています。
AWS CloudShellでのjqエラー
AWS CloudShellで、jqを使用する際に発生するエラーについて説明します。
数値が含まれる配列をjoin
しようとすると、jq: error string and number cannot be added
が出力されます。
期待する結果
$ echo '["example",0]' | jq 'join(".")'
"example.0"
実際の結果
$ echo '["example",0]' | jq 'join(".")'
jq: error (at <stdin>:1): string (".") and number (0) cannot be added
原因
このエラーの原因について説明します。
CloudShellにプリインストールされているjqのバージョンは、1.5です。1
$ jq --version
jq-1.5
1.5のjoinにはバグがあり、number型の場合に文字列化されないため、当該エラーが出力されます。
"def join($x): reduce .[] as $i (null; (.//\"\") + (if . == null then $i else $x + $i end))//\"\";",
このバグは1.6でFixされています。joinのソースを確認すると、number型をtostring
で文字列化していることがわかります。
def join($x): reduce .[] as $i (null;
(if .==null then "" else .+$x end) +
($i | if type=="boolean" or type=="number" then tostring else .//"" end)
) // "";
issueが上がっていました。
解決手段1(jq1.5で動作するように修正する)
このエラーを解決する手段について説明します。
まず、jq1.5で動作するように修正する方法です。
joinに渡す前に数値を文字列化すれば、1.5でも期待通りに動作します。もちろん1.6でも問題なく動作します。
$ echo '["example",0]' | jq 'map(.|tostring) | join(".")'
"example.0"
解決手段2(jq1.6をインストールする)
次は、jq1.6をCloudShellにインストールする方法です。
ただし、CloudShellで用意されているyumでは、プリインストールされているjqをアップグレードできない2ので、適当なディレクトリにバイナリをダウンロードするようにします。
ディレクトリの永続性について
-
/usr/bin
にバイナリファイルを配置すると、CloudShell再起動時にファイルが削除されるため、ご注意ください - ホームディレクトリに配置した場合はデータが永続化されますが、120日を超えて当該CloudShell環境の利用がないと、削除されますのでご注意ください
実際の例
具体的な例を示し、解決方法を説明します。
ホームディレクトリにインストール先のディレクトリを作成し、バイナリをダウンロードします。ディレクトリは任意ですが、ここではjq1.6
とします。
cd ~
mkdir jq1.6
cd jq1.6
wget -O jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod +x ./jq
先述のとおり、1.6でこのバグはFixされているので、期待通りに動作します。
$ ~/jq1.6/jq --version
jq-1.6
$ echo '["example",0]' | ~/jq1.6/jq 'join(".")'
"example.0"
エイリアスを設定すると、便利です。
$ echo "alias jq=~/jq1.6/jq" >> ~/.bashrc
# エイリアスをログイン中のシェルに反映
$ . ~/.bashrc
$ echo '["example",0]' | jq 'join(".")'
"example.0"
シェルスクリプトとして実行するには
シェルスクリプトとして実行する場合は、ログイン中のシェル環境が引き継がれないため、エイリアスが未定義となり、jq1.5が実行されてしまうことに注意する必要があります。
#!/bin/bash
echo '["example",0]' | jq 'join(".")'
$ bash ./join.sh
jq: error (at <stdin>:1): string (".") and number (0) cannot be added
この場合は、-i
オプションで対話的動作を指定すると、~/.bashrc
が読み込まれてスクリプトが実行されるため、期待通りの動作になります。
$ bash -i ./join.sh
"example.0"
結論
CloudShellで、jqを使用する際に発生するエラーについての対処法をまとめます。
2つの解決手段を説明しました。
解決手段1は、CloudShellの環境を変更する必要がなく、また、1.5と1.6どちらでも動作するため可搬性が高いことがメリットです。3
一方で、解決手段2は、1.6で動作させるので、joinエラー以外の挙動にも対応できることに優位性があります。
状況に応じて、使い分けてください。
参考