2016-12-13 5 views
4

주어진 필터가 JSON 데이터 구조에서 데이터를 가져 오는 데 성공했는지 알고 싶습니다. 예를 들면 :jq 필터가 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 데이터 구조에서 데이터를 가져 오지 않으면이 사실을 알아야합니다. 필터가 0이 아닌 반환 코드를 반환하는 것을 선호합니다.

선택기가 JSON 데이터 구조에서 데이터를 성공적으로 가져오고 데이터를 가져 오지 못하는 경우 어떻게 결정합니까?

중요 : 위의 필터는 예제 일 뿐이며 솔루션은 모든 jq 필터에서 작동해야합니다.

참고 : 평가 환경은 Bash 4.2 이상입니다.

+0

어떤 이유로 나는 당신의 질문에서 명령을 실행할 수 없습니다 (또는) 당신의 논리에서 플래그'-e'의 사용법을 시연 할 수 있습니다, 그것은'오류를 파싱합니다 : parse error : Line 6 , 25 열'내 Mac에서'jq-1.5'에 – Inian

+0

고정. 다시 시도하십시오. 값 키는 인용되지 않았습니다. 나는 위의 예제를 단순화하여'$ (whoami)'를'$ Name'으로 대체했다. 여기서'$ Name'은 스크립트 위의 줄에 명확하게 정의되어있다. –

+0

따옴표로 말하면'--arg Name "$ Name"'을 사용하십시오. 그렇지 않으면 이름이 파싱되는 셸 단어의 수는 완전히 정의되지 않습니다. –

답변

1

내 요구 사항을 모두 충족하는 솔루션을 찾았습니다. 당신의 생각을 알려주세요!

아이디어는 첫 번째 통과 확인으로 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*** 
+0

좋은 소리! 나중에 참조 할 수 있도록 대답을 받아 들여야합니다! – Inian

+1

I 내가 받아 들일 수있을 때까지 2 일을 기다려야한다고 생각해. 제발 대답을 upvote ... 난 그냥 물건을 여기에 퍼팅 시작하고 평판 포인트가 필요해! :-) 나는 정말 당신과 앞뒤로 즐겼다. . 나는 너와 대화를 나눌 수 있기를 희망한다. 많은 감사합니다! –

+0

이것은 지나치게 복잡하게 보입니다. @ peak의 답을 보거나 광산을 봅니다. – Thedward

3

당신은 당신의 주어진 예를 들어 나를 위해 작동하지 않습니다으로

Sets the exit status of jq to 0 if the last output values was neither false nor null, 1 if the last output value was either false or null, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran.

내가 아래와 같이 기본 필터 사용을 보여줄 수 말한다 jq Manual,에서 -e/--exit-status 플래그를 사용할 수 있습니다. 나는 이중에 의해 만들어진 코드 2 반환 존재하지 않는 개체 zoo 함께 할 쿼리에 성공

, 잘못된 쿼리

dudeOnMac:~$ jq -e '.foo?' <<< '{"foo": 42, "bar": "less interesting data"}' 
42 
dudeOnMac:~$ echo $? 
0 

, 오류 시나리오의

dudeOnMac:~$ jq -e '.zoo?' <<< '{"foo": 42, "bar": "less interesting data"}' 
null 
dudeOnMac:~$ echo $? 
1 

, jq 입력 스트림을 표시합니다.

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 
+0

위의 예제를 다시 시도하십시오. 나는 제인 사용자에 대한 가치를 언급하지 않았다. 나는 그것을 위에 고쳤다.-e 플래그를 사용하면 존재하지 않는 키에 대해 0이 아닌 오류 코드를 제공하지만, ** badly ** 값이 'false'또는 'false'인 기존 키에 대해 0이 아닌 오류 코드를 제공합니다. 널'이다. 그래서, 이것은 확실히 작동하지 않을 것입니다. 값에는 부울 값, 빈 문자열 및 'null'이 포함될 수 있다는 것이 매우 분명합니다. 다른 생각이 있습니까? –

+0

@SteveAmerige : 좋은 관찰입니다. 이것들이 종료 코드이고,'jq'가 지원 합니다만,'1' 코드와 그 코드 이외의 다른 코드와 분명히 구별 될 수 있습니다. 아마 그 논리를 사용할 수 있을까요? – Inian

+0

-e 플래그를 사용하면이 문제로 인해 반환 상태가 0 인 경우 결과가 JSON 데이터에서 나온 것으로 결론 내릴 수 있습니다. 0이 아닌 경우, 1이 아닌 오류 상태 : 결과가 어떤 식 으로든 잘못되었습니다 (실제 오류 경우). 1 오류 상태 : 결과가 false이면 JSON 데이터에서 실제로 나온 결과이므로 0 반환 상태로 처리합니다. ** 마지막 사례는 반환 상태가 1이고 결과가 null 인 경우입니다. ** 데이터가 JSON 입력에서 온 것인지 아닌지를 알 수있는 방법을 아직 알지 못했습니다. 이를 해결할 수 있다면 문제는 해결됩니다. jq 필터는 무엇이든 될 수 있다는 것을 명심하십시오. 그래서,'has()'는 도움이되지 않습니다. –

1

JQ이 인 방법이라고, 특히 그것이 내가, 스트림 지향적 인 점을 감안 더 나은 접근법은 원하는 구별을 만드는 하나 이상의 필터를 정의하고 사용하는 것이라고 생각하는 경향이 있습니다.따라서 오히려 필드의 값에 액세스 할 수 .a를 작성하는 대신, 다음과 같이 그/1 정의 얻을 가정 get("a")을 써서 : 이제

def get(f): if has(f) then .[f] else error("\(type) is not defined at \(f)") end; 

쉽게 객체가 키가 있는지 여부를 알 수 있습니다, 그리고 너는 모두 갈 준비가되어있다. get의이 정의는 배열에서도 사용할 수 있습니다.

+0

당신은 저를 때려 눕 힙니다!또한 정의 된대로'get'이 이미 배열로 잘 작동한다는 것을 지적하고 싶습니다. – Thedward

+0

@Thedward - 객체와 배열 모두에 대해 if를 사용하는 것이 의미가 있도록 def를 업데이트했습니다. – peak

0

여기

근본적인 문제 아래에 업데이트 된 솔루션입니다 추가 한 것을 시도는 .key 또는 .[key] 구문, jq를 사용하여 객체에서 값을 검색 할 때 - 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를 사용하는 경우, 그 줄 것이라고 생각 당신이 원하는 행동.


여기에 적은 bashjq로, 그것에 대해 이동하는 또 다른 방법입니다. 추천 -

steve 0 false 
tom  0 true 
pat  0 null 
jane 0 "" 
mary 5 ***ERROR*** 

empty 같은 필터 작용에 실제로 입력의 유무를 활용하고, 빈 //의 대체를 실행하지만 문자열 :

#!/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 

출력을 생성 "null" 또는 "false" - 그렇지 않습니다.

value/1은 개체/배열에 간단한 키/인덱스 조회의 필터는 작동하지 않지만 어느 솔루션도 사용할 수 없습니다. 내가 에 모든 경우를 포함 것을 합리적으로 확신,이 같은 (또는 당신) get 또는 lookup 같은 뭔가 필요 했어.

+0

이 솔루션은 너무 좁습니다. jq 필터는 반드시 간단한 키 선택 자일 필요는 없습니다. 내 의견을 내 자신의 솔루션으로보십시오. 참여해 주셔서 다시 한 번 감사드립니다. –

+0

더 흥미로운 솔루션은 f.i .:'lookup (.a.b.c)'을 재귀 적으로 검색하는 것입니다. json에'.a.b.c'가 있으면, 그것을 반환하거나 그렇지 않으면 에러를 던집니다. 나는 우리가'has','path','map'과 같은 몇 가지 jq 함수를 사용할 필요가 있다고 믿습니다. [a],. [b]. [c] .a.b.c가 존재하는지 알아보기 위해 모든 항목에 재귀 적으로 걸어 가야합니다. – jsxt

+0

연말 연시와 모든 반응에 늦어서 죄송합니다. 업데이트가 매우 흥미 롭습니다. 너무 많아서 이제 이것을 받아 들인 대답으로 바꾸는 것을 고려하고 있습니다. Bash 측에서 필터를 검사하여 정규 경로 필터 (예 :'.a [1] .b')인지 확인하기 위해 정규식 검사를 수행하면 그 필터를 다음과 같이 처리 할 수 ​​있습니다. 경로가 존재하는지 여부를 결정하기 위해 걷기가 필요한 별도의 사례. 간단한 경로 필터가 아니라면 위의 방법을 사용하십시오. 이 필터가 모든 필터에서 작동한다고 생각하십니까? 산책하는 법을 설명해 주시겠습니까? –