问题
I have an array and I need to check if elements exists in that array or to get that element from the array using jq, fruit.json:
{
"fruit": [
"apple",
"orange",
"pomegranate",
"apricot",
"mango"
]
}
cat fruit.json | jq '.fruit .apple'
does not work
回答1:
The semantics of 'contains' is not straightforward at all. In general, it would be better to use 'index' to test if an array has a specific value, e.g.
.fruit | index( "orange" )
IN/1
If your jq has IN/1
then a better solution is to use it:
.fruit as $f | "orange" | IN($f[])
If your jq has first/1
(as does jq 1.5), then here is a fast definition of IN/1
to use:
def IN(s): first((s == .) // empty) // false;
回答2:
[WARNING: SEE THE COMMENTS AND ALTERNATIVE ANSWERS.]
cat fruit.json | jq '.fruit | contains(["orange"])'
回答3:
To have jq
return success if the array fruit
contains "apple"
, and error otherwise:
jq -e '.fruit[]|select(. == "apple")' fruit.json >/dev/null
To output the element(s) found, omit >/dev/null
. If searching for a fixed string, this isn't very relevant, but it might be if the select
expression might match different values, e.g. if it's a regexp.
To output only distinct values, pass the results to unique
.
jq '[.fruit[]|select(match("^app"))]|unique' fruit.json
will search for all fruits starting with app
, and output unique values. (Note that the original expression had to be wrapped in []
in order to be passed to unique
.)
回答4:
For future visitors, if you happen to have the array in a variable and want to check the input against it, and you have jq 1.5 (without IN), your best option is index
but with a second variable:
.inputField as $inputValue | $storedArray|index($inputValue)
This is functionally equivalent to .inputField | IN($storedArray[])
.
回答5:
If you're open to using something other than jq
, then I can highly recommend Xidel.
With it you can combine JSONiq and XPath/XQuery to process JSON!
To have it simply return a boolean:
$ xidel -s fruit.json -e '$json/contains((fruit)(),"apple")'
true
To have it return the element if the array fruit
contains "apple":
$ xidel -s fruit.json -e '$json/(fruit)()[contains(.,"apple")]'
apple
Above is "XPath notation". "Dot notation" (like jq
):
$ xidel -s fruit.json -e '($json).fruit()[contains(.,"apple")]'
apple
回答6:
Also, there's been developed another alternative JSON manipulation unix tool now, offering a novel approach to handle JSONs - walk-path
unix utility jtc.
Here are some examples how to achieve the ask:
1. When entry exists - it'll be printed, otherwise a blank returned:
bash $ <fruit.json jtc -w'<apple>'
"apple"
bash $ <fruit.json jtc -w'<plum>'
bash $
2. When entry exists print true
, otherwise print false
:
bash $ <fruit.json jtc -w'<res:false>f<apple><res:true>v' -T'{{res}}'
true
bash $ <fruit.json jtc -w'<res:false>f<plum><res:true>v' -T'{{res}}'
false
bash $
3. When entry is present print it, otherwise print "FALSE"
:
bash $ <fruit.json jtc -w'<r:"FALSE">f<apple><r>v' -T'{{r}}'
"apple"
bash $ <fruit.json jtc -w'<r:"FALSE">f<plum><r>v' -T'{{r}}'
"FALSE"
bash $
PS. Disclosure: I'm the creator of the jtc
- shell cli tool for JSON operations
PSS. disclosure of affiliation with the product is required by SO.
来源:https://stackoverflow.com/questions/43259563/how-to-check-if-element-exists-in-array-with-jq