特定のフィルターがJSONデータ構造からデータをプルすることに成功したかどうかを知りたいです。例えば:
###### For the user steve...
% Name=steve
% jq -j --arg Name "$Name" '.[]|select(.user == $Name)|.value' <<<'
[
{"user":"steve", "value":false},
{"user":"tom", "value":true},
{"user":"pat", "value":null},
{"user":"jane", "value":""}
]'
false
% echo $?
0
注:成功した結果には、ブール値、null
、さらには空の文字列が含まれる可能性があります。
###### Now for user not in the JSON data...
% Name=mary
% jq -j --arg Name "$Name" '.[]|select(.user == $Name)|.value' <<<'
[
{"user":"steve", "value":false},
{"user":"tom", "value":true},
{"user":"pat", "value":null},
{"user":"jane", "value":""}
]'
% echo $?
0
フィルタがJSONデータ構造からデータをプルしない場合は、これを知る必要があります。フィルタがゼロ以外のリターンコードを返すことをお勧めします。
セレクターがJSONデータ構造からデータを正常にプルするのか、データをプルできないのかを判断するにはどうすればよいですか?
重要:上記のフィルターは単なる例であり、ソリューションはすべてのjqフィルターで機能する必要があります。
注:評価環境はBash4.2以降です。
すべての要件を満たすソリューションを見つけました!ご意見をお聞かせください!
アイデアは、ファーストパスチェックとして_jq -e "$Filter"
_を使用することです。次に、戻りコード1の場合、jq "path($Filter)"
チェックを実行します。後者は、実際にJSONデータへのパスがある場合にのみ成功します。
Select.sh
_#!/bin/bash
Select()
{
local Name="$1"
local Filter="$2"
local Input="$3"
local Result Status
Result="$(jq -e --arg Name "$Name" "$Filter" <<<"$Input")"
Status=$?
case $Status in
1) jq --arg Name "$Name" "path($Filter)" <<<"$Input" >/dev/null 2>&1
Status=$?
;;
*) ;;
esac
[[ $Status -eq 0 ]] || Result="***ERROR***"
echo "$Status $Result"
}
Filter='.[]|select(.user == $Name)|.value'
Input='[
{"user":"steve", "value":false},
{"user":"tom", "value":true},
{"user":"pat", "value":null},
{"user":"jane", "value":""}
]'
Select steve "$Filter" "$Input"
Select tom "$Filter" "$Input"
Select pat "$Filter" "$Input"
Select jane "$Filter" "$Input"
Select mary "$Filter" "$Input"
_
そして、上記の実行:
_% ./Select.sh
0 false
0 true
0 null
0 ""
4 ***ERROR***
_
-e / --exit-status
からjq Manual
フラグを使用できます。
最後の出力値がfalseでもnullでもなかった場合はjqの終了ステータスを0に設定し、最後の出力値がfalseまたはnullでなかった場合は1に設定し、有効な結果が生成されなかった場合は4に設定します。通常、jqは、使用上の問題またはシステムエラーがあった場合は2、jqプログラムのコンパイルエラーがあった場合は3、jqプログラムが実行された場合は0で終了します。
あなたの与えられた例は私のために働いていないので、私は以下のような基本的なフィルターでの使用法を示すことができます。
クエリを成功させるには、
dudeOnMac:~$ jq -e '.foo?' <<< '{"foo": 42, "bar": "less interesting data"}'
42
dudeOnMac:~$ echo $?
0
存在しないエンティティZoo
で行われた無効なクエリの場合、
dudeOnMac:~$ jq -e '.zoo?' <<< '{"foo": 42, "bar": "less interesting data"}'
null
dudeOnMac:~$ echo $?
1
エラーシナリオの場合、jq
入力ストリームを二重引用符で囲んで作成したコード2
を返します。
dudeOnMac:~$ jq -e '.zoo?' <<< "{"foo": 42, "bar": "less interesting data"}"
jq: error: Could not open file interesting: No such file or directory
jq: error: Could not open file data}: No such file or directory
dudeOnMac:~$ echo $?
2
Jqが現状であり、特にストリーム指向であることを考えると、より良いアプローチは、必要な区別を行う1つ以上のフィルターを定義して使用することだと思う傾向があります。したがって、フィールドの値にアクセスするために_.a
_を記述するのではなく、get/1が次のように定義されていると仮定してget("a")
を記述します。
_def get(f): if has(f) then .[f] else error("\(type) is not defined at \(f)") end;
_
これで、オブジェクトにキーがあるかどうかを簡単に判断でき、準備が整いました。このget
の定義は、配列でも使用できます。
以下に更新されたソリューションを追加しました
ここでの基本的な問題は、_.key
_または_.[key]
_構文を使用してオブジェクトから値を取得しようとすると、jq
— by definition —が欠落しているキーを区別できないことです。値がnull
のキー。
代わりに、独自のルックアップ関数を定義できます。
_def lookup(k):if has(k) then .[k] else error("invalid key") end;
_
次に、次のように使用します。
_$ jq 'lookup("a")' <<<'{}' ; echo $?
jq: error (at <stdin>:1): invalid key
5
$ jq 'lookup("a")' <<<'{"a":null}' ; echo $?
null
0
_
次に、組み込みメソッドの代わりにlookup
を一貫して使用すると、希望する動作が得られると思います。
bash
を減らし、jq
を増やす、別の方法があります。
_#!/bin/bash
lib='def value(f):((f|tojson)//error("no such value"))|fromjson;'
users=( steve tom pat jane mary )
Select () {
local name=$1 filter=$2 input=$3
local -i status=0
result=$( jq --arg name "$name" "${lib}value(${filter})" <<<$input 2>/dev/null )
status=$?
(( status )) && result="***ERROR***"
printf '%s\t%d %s\n' "$name" $status "$result"
}
filter='.[]|select(.user == $name)|.value'
input='[{"user":"steve","value":false},
{"user":"tom","value":true},
{"user":"pat","value":null},
{"user":"jane","value":""}]'
for name in "${users[@]}"
do
Select "$name" "$filter" "$input"
done
_
これにより、次の出力が生成されます。
_steve 0 false
tom 0 true
pat 0 null
jane 0 ""
mary 5 ***ERROR***
_
これは、フィルターへの入力がないことはempty
のように機能し、空は_//
_の代替をトリガーしますが、_"null"
_や_"false"
_のような文字列はトリガーしないという事実を利用します。
_value/1
_は、オブジェクト/配列の単純なキー/インデックスルックアップであるフィルターでは機能しませんが、ソリューションでも機能しないことに注意してください。すべてのケースをカバーするには、このようなもの(またはあなたのもの)が必要になると確信していますandget
またはlookup
のようなもの。