jq built-in method select(): command not found - shell

I used the jq built-in method select to parse the json string in shell script, and got an error: command not found.
Here is my shell script: test.sh
#!/bin/bash
function test(){
json='[{"id":1,"name":"jdjson"},{"id":2,"name":"imagetookit"}]'
detail=`echo $json | jq .[]|select\(.id==2\)`
}
test
I just ran the script on the command line and got the following error:
$ bash test.sh
test.sh:行5: select(.id==2): 未找到命令 (means "command not found")
the select is built-in method of jq command, and I don't know why
Does the function need to be imported? How to import method of jq?

It's not a jq problem, it's a shell quoting issue:
mytest(){
json='[{"id":1,"name":"jdjson"},{"id":2,"name":"imagetookit"}]'
detail=$(echo "$json" | jq '.[]|select(.id==2)')
echo "$detail"
}
mytest
{
"id": 2,
"name": "imagetookit"
}
Notice the single quote ' around the jq command and so no need for backslash \.
Also prefer the $(...) instead of the old backtick notation.

Related

How to pass environment bash variables into json using jq [duplicate]

I want to populate json template with value "Hello Jack", but the "Hello" part shall remain inside of template, is there are any way of doing that, I've tried code below but it gives me error:
jq -n --arg person "Jack" '{my_key: "Hello "$person}'
jq: error: syntax error, unexpected '$', expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
Use string interpolation syntax like so:
jq -n --arg person Jack '{my_key: "Hello \($person)"}'
And to load the template from a file, use the -f switch:
$ cat template.json
{
"my_key": "Hello \($person)"
}
$ jq -n --arg person Jack -f template.json
{
"my_key": "Hello Jack"
}

jq produces `is not defined at <top-level>` error

I'm seeing a is not defined at <top-level> when calling jq like so:
jq ".Changes[0].ResourceRecordSet.Name = word-is-here.domain.com" someFile.json
The error repeats for each word separated by a dash in the second side of the replacement. The full error is like
jq: error: word/0 is not defined at <top-level>, line 1:
.Changes[0].ResourceRecordSet.Name = word-is-here.domain.com
I've tried escaping quotes in many different ways but that didn't help. (what I mean by this is doing "'"'" weird stuff, I'm still learning bash so I'm just trowing stuff at the wall until it sticks)
EDIT:
So I'm trying to run this in a bash script, and both side of the = signs are variables such as jq --arg value "$value" --arg key "$key" '$key = $value' "$path" (what I tried after a suggestion)
and got the error:
Invalid path expression with result ".Changes[0].ResourceRecor...
The json I'm using is as such:
{
"Changes": [
{
"Action": "do something",
"ResourceRecordSet": {
"Name": "some name here to replace",
...
}
}
]
}
jq '.Changes[0].ResourceRecordSet.Name = "word-is-here.domain.com"' file.json
Quote the string you are assigning. Or pass it to jq via an argument:
jq --arg foo 'words-here' '.Changes[0].ResourceRecordSet.Name = $foo' file.json
For passing the path to the key you want as an argument, a suggestion from https://github.com/stedolan/jq/issues/1493 might work:
jq --argjson path '["Changes",0,"ResourceRecordSet","Name"]' \
--arg val 'word-is-here.domain.com' \
'getpath($path) = $val' file.json
The problem (or at least the obvious problem) here is evidently the string: word-is-here.domain.com, since jq is interpreting the dash ("-") as an operation ("minus").
Unfortunately, since you haven't given us many clues, it's not completely clear what specifically needs to be changed, but a reasonable guess is that word-is-here.domain.com is intended as a fixed string. If so, you would have to present it as a JSON string. So in a bash or bash-like environment, you could write:
jq '.Changes[0].ResourceRecordSet.Name = "word-is-here.domain.com"' someFile.json
Specifying the LHS path via a shell variable
If the LHS path must be specified by a shell variable, it should if possible be passed in as a JSON array, e.g. using the --argjson command-line option; one can then use an expression of the form setpath($path; $value) to update the path.
If for some reason a solution allowing the LHS to be specified as a jq path is preferred, then shell string-interpolation could be used, though as with any such interpolation, this should be done with care.

Why are spaces required before a curly brace in a function definition?

I'm trying to create a bash script that converts a bunch of pdfs into text in order to extract some information but the shell gives me this error:
./AutoBib.sh: line 8: syntax error near unexpected token `pdftotext'
./AutoBib.sh: line 8: ` pdftotext $1 temp.txt'
Here there is an example of my function:
function doi{
pdftotext $1 temp.txt
cat temp.txt | grep doi: | cut -d: -f 2 | head -n 1 >> dois.txt
rm -rf temp.txt
}
doi $PDF
Where the variable PDF is taken in input. Before adding the function it worked, I used to write in my script:
pdftotext $PDF tempo.txt
From Bash manual:
The braces are reserved words, so they must be separated from the list
by blanks or other shell metacharacters.
function ... is an outdated syntax for defining Bash functions. Use this instead:
doi() {
...
}
Since () are meta characters, you don't need a space in this case (though spaces make your code prettier):
doi(){
...
}
Extending this a little, remember that we need a whitespace (space, tab, or newline) after { and before `}' in command grouping, like this:
{ command1; command2; ... }
You need a space after the name of your function and before the {:
function doi {
^

Bash/JQ - parse error: Expected separator between values at line 1, column 63

I'm having what I suspect is a quoting error in a bash script.
SECRET_VALUE_CMD="curl -s -L -H \"X-Vault-Token: $VAULT_TOKEN\" -X GET \"https://$VAULT_ADDR/v1/secret/$secret_path\""
SECRET_VALUE_RESPONSE=$(eval $SECRET_VALUE_CMD)
SECRET_VALUE=$(echo "$SECRET_VALUE_RESPONSE" | jq --raw-output '.data.value')
When I execute this in my script, I get the following to stderr:
parse error: Expected separator between values at line 1, column 63
and $SECRET_VALUE is blank.
An example of $SECRET_VALUE_RESPONSE is:
{"request_id":"XXXX-YYYY..,"lease_id":"","renewable":false,"lease_duration":nnnnnn,"data":{"value":"secret-value"},"wrap_info":null,"warnings":null,"auth":null}
I've tried adding escaped quotes around the parameters to eval and echo, but can't seem to find a working combination. Any help would be greatly appreciated!
Don't use eval. You could create a function to execute curl, for example:
get_secret_value() {
curl -s -L -H "X-Vault-Token: $VAULT_TOKEN" -X GET "https://$VAULT_ADDR/v1/secret/$secret_path"
}
secret_value=$(get_secret_value | jq --raw-output '.data.value')

How to create for-loops with jq in bash

I'm trying to split a json file into various json files. The input (r1.json) looks like :
{
"results" : [
{
content 1
}
,
{
content 2
}
,
{
content n
}
]
}
I'd like the output to be n files : 1.json, 2.json, n.json. Respectively containing {content 1}, {content 2} and {content n}.
I tried :
for i in {0..24}; do cat r1.json | jq '.results[$i]' >> $i.json; done
But I have the following error: error: i is not defined
While the above answers are correct, note that interpolating shell variables in jq scripts is a terrible idea for all but the most trivial of scripts. On any of the solutions provided, replace the following:
jq ".results[$i]"
With the following:
jq --arg i "$i" '.results[$i | tonumber]'
Try
for i in {0..24}; do cat r1.json | jq ".results[$i]" >> $i.json; done
Note that shell variables can't be expanded inside of single-quotes.
IHTH
The single quotes are probably what is messing you up. Bash variables are not expanded in single quotes. You are passing a literal string .results[$i] to jq. Try double quotes instead:
for i in {0..24}; do
cat r1.json | jq ".results[$i]" >> $i.json
done

Resources