I actually have 2 arrays in bash that contains string values.
Something like that :
Array1=(Kevin Paul)
Array2=(OK DANGER)
I would like to create a json with 2 attributes, something like that if possible
{
"results":[
{
"nom":"Kevin",
"status":"OK"
},
{
"nom":"Paul",
"status":"Danger"
}
]
}
I read a lot speaking about JQ that i alreay use for my arrays, but no one speak about something like i want :(
One of my test ( that does not respond to what i would like ) :
declare -a test_array
declare -a test_array2
test_array=(apple orange lemon)
test_array2=(DANGER OK WARNING)
echo ${test_array[0]}
echo '['
printf '{"CVEC": "%s", "LVL" : "%s"},\n' "${test_array[#]}, ${test_array2[#]}" | sed '$s/,$//'
echo ']'
Display
[
{"CVEC": "apple", "LVL" : "orange"},
{"CVEC": "lemon, DANGER", "LVL" : "OK"},
{"CVEC": "WARNING", "LVL" : ""}
]
Using a template engine: perl's Template::Toolkit command line tool: tpage:
Files
header:
{
"results":[
footer:
]
}
file.tpl (template):
{
"nom": "[% x1 %]",
"status": "[% x2 %]"
}[% sep %]
Bash script
#!/bin/bash
arr1=( Kevin Paul )
arr2=( OK danger )
{
cat header
for i in "${!arr1[#]}"; do
((i==${#arr1[#]}-1)) && sep='' || sep=','
tpage --define x1="${arr1[i]}" \
--define x2="${arr2[i]}" \
--define sep=$sep file.tpl
done
cat footer
} | tee file.json
Validation
$ jq . file.json
{
"results": [
{
"nom": "Kevin",
"status": "OK"
},
{
"nom": "Paul",
"status": "danger"
}
]
}
Package
For debian and debian like:
apt install libtemplate-perl
Via CPAN:
cpan -i Template::Toolkit
Check http://www.template-toolkit.org/docs/tools/tpage.html
One way:
paste <(printf "%s\n" "${Array1[#]}") <(printf "%s\n" "${Array2[#]}") |
jq -nRc '{ results: [inputs] | map(split("\t") | { nom: .[0], status: .[1] }) }'
produces
{"results":[{"nom":"Kevin","status":"OK"},{"nom":"Paul","status":"DANGER"}]}
This assumes that the elements of your arrays do not have tabs or newlines in them. It uses paste to generate pairs of corresponding array elements, separated by tabs, one pair per line, and then uses jq to create the JSON output from that.
If the objective is to stick with a non-jq solution - and chepner's comments about needing to validate the array entries is not an issue for this situation - one idea would be to loop through the array indices.
Test data:
$ declare -a test_array=(apple orange lemon)
$ typeset -p test_array
declare -a test_array=([0]="apple" [1]="orange" [2]="lemon")
$ declare -a test_array2=(DANGER OK WARNING)
$ typeset -p test_array2
declare -a test_array2=([0]="DANGER" [1]="OK" [2]="WARNING")
A simple loop through the indices (0,1,2):
sfx=',' # default printf suffix is a comma
for (( i=0 ; i<${#test_array[#]} ; i++ ))
do
(( ${i} == ( ${#test_array[#]} - 1 ) )) && sfx='' # clear suffix for last pass through loop
printf '{"CVEC": "%s", "LVL" : "%s"}%s\n' "${test_array[${i}]}" "${test_array2[${i}]}" "${sfx}"
done
Which generates the following:
{"CVEC": "apple", "LVL" : "DANGER"},
{"CVEC": "orange", "LVL" : "OK"},
{"CVEC": "lemon", "LVL" : "WARNING"}
Related
I need to put the json keys of a file as a array in a shell script how can i do that?
{
"employee4" : {
"aliases" : { }
},
"employee3" : {
"aliases" : { }
},
"employee" : {
"aliases" : { }
},
"employee2" : {
"aliases" : { }
}
}
I need to have a array like keys["employee", "employee2", "employee3", "employee4"]
If there is more keys the array need to find them
The jq keys function returns a list of keys. So with your example data in data.json, we see:
$ jq 'keys' data.json
[
"employee",
"employee2",
"employee3",
"employee4"
]
To get rid of the JSON list, we run:
$ jq -r 'keys[]' data.json
employee
employee2
employee3
employee4
And to get that into a bash array:
myarray=( $(jq -r 'keys[]' data.json) )
As #glennjackman mentions in a comment, the above construct will have problems if your keys contain whitespace or shell special characters. For example, given this data:
{
"employee*" : {
"aliases" : { }
}
}
If your directory contains files named employee1 and employee2, then you'll get, effectively:
myarray=( employee1 employee2 )
...which is not what you want. You can fix this by using the mapfile builtin (also known as readarray, which makes its purpose more obvious):
mapfile -t myarray < <(jq -r 'keys[]' data.json)
The JSON-parser xidel can do what you want.
To return the JSON keys / attributes:
$ xidel -s input.json -e '$json()' # or -e 'map:keys($json)'
employee4
employee3
employee
employee2
To create the Bash array:
$ mapfile -t myArr < <(xidel -s input.json -e '$json()')
Alternatively, xidel can do this too with --output-format=bash:
$ eval "$(xidel -s input.json -e 'myArr:=$json()' --output-format=bash)"
In both cases this will result in:
$ printf '%s\n' "${myArr[*]}" ${#myArr[*]} ${myArr[0]} ${myArr[1]}
employee4 employee3 employee employee2
4
employee4
employee3
I have a list of images and their respective tags in a given images.json file, like below:
{
"image1":"1.1",
"image2": "1.2",
"image3": "1.3"
}
I was able to use a sed command to read values from above images.json and store each column in an array , such as
image=${arraydata[0]}
tag=${arraydata[1]}
For each image, I would like to compare if its tag exists in the below output I get from a curl command:
curl -X GET https://docker.jfrog.io/artifactory/api/docker/docker-local/v2/$image/tags/list?
Output of above:
{
"name" : "image1",
"tags" : [ "1.1", "1.2" ]
}{
"name" : "image2",
"tags" : [ "1.1", "1.2", "1.3" ]
}{
"name" : "image3",
"tags" : [ "1.1", "1.2", "1.4" ]
}
I would like to have an if/else statement to check if tag for an image exists in the results above:
If exists then do nothing
Else do docker push jfrog/$image:$tag
Perhaps (untested)
assumes your shell is bash
uses jq for your JSON-parsing needs
declare -A versions
while IFS=$'\t' read -r img ver; do
versions[$img]=$ver
done < <(
jq -r '. as $obj | keys[] | [., $obj[.]] | #tsv' images.json
)
# versions=([image1]="1.1" [image2]="1.2" [image3]="1.3" )
for img in "${!versions[#]}"; do
ver=${versions[$img]}
url="https://docker.jfrog.io/artifactory/api/docker/docker-local/v2/$img/tags/list?"
artifacts=$(curl -X GET "$url")
result=$(jq --arg ver "$ver" '.tags | contains([$ver])' <<<"$artifacts")
if [[ $result == true ]]; then
echo "image $img has version $ver"
else
echo "image $img does not have version $ver"
fi
done
status=$(wget --spider --server-response http://any_url:5000/v2/repository/image-name-you-query/manifests/latests 2>&1 | grep "HTTP/" | awk '{print $2}')
This snipped will print 200 if the image exists and something else if tehre is any problem. Particularly, if it does not exist, you will get 404.
You can then leverage this in your shell script like this:
if [ $status -eq 200 ]; then
# do something
else
# do something else
fi
I have a dictionary that looks like this:
{
"uid": "d6fc3e2b-0001a",
"name": "ABC Mgmt",
"type": "host"
}
{
"uid": "d6fc3e2b-0002a",
"name": "Server XYZ",
"type": "group"
}
{
"uid": "d6fc3e2b-0003a",
"name": "NTP Primary",
"type": "host"
}
{
"uid": "d6fc3e2b-0004a",
"name": "H-10.10.10.10",
"type": "host"
}
Then I have a txt file:
"d6fc3e2b-0001a"
"d6fc3e2b-0001a","d6fc3e2b-0002a","d6fc3e2b-0003a"
"d6fc3e2b-0004a"
Expected Output:
"ABC Mgmt"
"ABC Mgmt","Server XYZ","NTP Primary"
"H-10.10.10.10"
I have some trouble to make jq using an array which is not json format. I tried various solutions that I found, but none of them worked. I am rather new to scripting, need some help.
input=file.txt
while IFS= read -r line
do
{
value=$(jq -r --arg line "$line" \
'from_entries | .[($line | split(","))[]]' \
dictionary.json)
echo $name
}
done < "$input"
In the following solution, the dictionary file is read using the --slurpfile command-line option, and the lines of "text" are read using inputs in conjunction with the -n command-line option. The -r command-line option is used in conjunction with the #csv filter to produce the desired output.
Invocation
jq -n -R -r --slurpfile dict stream.json -f program.jq stream.txt
program.jq
(INDEX($dict[]; .uid) | map_values(.name)) as $d
| inputs
| split(",")
| map(fromjson)
| map($d[.])
| #csv
Caveat
The above assumes that the quoted values in stream.txt do not themselves contain commas.
If the quoted values in stream.txt do contain commas, then it would be much easier if the values given on each line in stream.txt were given as JSON entities, e.g. as an array of strings, or as a sequence of JSON strings with no separator character.
Solution to problem described in a comment
Invocation
< original.json jq -r --slurpfile dict stream.json -f program.jq
program.jq
(INDEX($dict[]; .uid) | map_values(.name)) as $d
| .source
| map($d[.])
| #csv
I have one json e.g
var bbview ={
"tbl_am_api":[
{
"Modified_User":"user1",
"Modified_Time":"04-Jul-2018 01:40:05",
"Line_Number":"SS001",
"Service_Type":"BB3",
"Status":"Yes",
"ID":3144526000014337832,
"Added_Time":"04-May-2018 11:37:29"
},
{
"Modified_User":"user2",
"Modified_Time":"04-Jul-2018 01:40:05",
"Line_Number":"SS002",
"Service_Type":"BB2",
"Status":"Yes",
"ID":3144526000014337832,
"Added_Time":"04-May-2018 11:37:29"
},
{
"Modified_User":"user3",
"Modified_Time":"04-Jul-2018 01:40:05",
"Line_Number":"SS004",
"Service_Type":"BB1",
"Status":"No",
"ID":3144526000014337832,
"Added_Time":"04-May-2018 11:37:29"
}
]
};
I want to compare this json data and array. Primary key as Line Number.
arrayA = {[{Line_Number : SS001, Service_Type : BB3; Status : Yes}]}
arrayA have Line_Number SS001. Find this Line_Number in json and compare Service_Type value and Status value are same or not. I want to write with Shell Script in bash file. I am not proficient in shell script. Please help me.
Update:
I tried with following bash code. But still fail. Please advice me
echo "Download FMS AM API File"
rm -rf tbl_am_api_Report?authtoken=da84d49f334c33b88d30dd2c947a4ff0 && wget -q https://creator.zoho.com/api/json/fixed-management-system/view/tbl_am_api_Report?authtoken=da84d49f334c33b88d30dd2c947a4ff0&scope=creatorapi&zc_ownername=tmlbroadband < /dev/null
cat > tbl_api_Report?authtoken=da84d49f334c33b88d30dd2c947a4ff0 //read json file
for row in $(echo "${apiview}" | jq -r '.[] | #base64'); do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
echo $(_jq '.name') >> info.txt
done
mail -s "Test email" aa#gmail.com -A info.txt < /dev/null
The value of arrayA is not JSON so I am going to let you figure out how to extract the values of Line_Number and Status from arrayA (but see below). Once those values are available, one could proceed as illustrated here:
#!/bin/bash
bbview='...' # as above
echo "$bbview" |
jq --arg Line_Number SS001 --arg Status Yes '
.tbl_am_api
| map(select(.Line_Number==$Line_Number and .Status==$Status)) '
Output
[
{
"Modified_User": "user1",
"Modified_Time": "04-Jul-2018 01:40:05",
"Line_Number": "SS001",
"Service_Type": "BB3",
"Status": "Yes",
"ID": 3144526000014338000,
"Added_Time": "04-May-2018 11:37:29"
}
]
true/false
Under a different reading of the question, the following variant might be relevant:
echo "$bbview" |
jq --arg Line_Number SS001 --arg Status Yes '
.tbl_am_api
| map(select(.Line_Number==$Line_Number) | .Status==$Status) '
arrayA
If you are using a version of bash that supports associative arrays, you could define arrayA as an associative array, like so:
declare -A arrayA
arrayA=([Line_Number]=SS001 [Service_Type]=BB3 [Status]=Yes)
Then to retrieve the value associated with Line_Number, you would write: ${arrayA[Line_Number]}; etc.
I'm parsing a JSON response with a tool called jq.
The output from jq will give me a list of full names in my command line.
I have the variable getNames which contains JSON, for example:
{
"count": 49,
"user": [{
"username": "jamesbrown",
"name": "James Brown",
"id": 1
}, {
"username": "matthewthompson",
"name": "Matthew Thompson",
"id": 2
}]
}
I pass this through JQ to filter the json using the following command:
echo $getNames | jq -r .user[].name
Which gives me a list like this:
James Brown
Matthew Thompson
I want to put each one of these entries into a bash array, so I enter the following commands:
declare -a myArray
myArray=( `echo $getNames | jq -r .user[].name` )
However, when I try to print the array using:
printf '%s\n' "${myArray[#]}"
I get the following:
James
Brown
Matthew
Thompson
How do I ensure that a new index is created after a new line and not a space? Why are the names being separated?
Thanks.
A simple script in bash to feed each line of the output into the array myArray.
#!/bin/bash
myArray=()
while IFS= read -r line; do
[[ $line ]] || break # break if line is empty
myArray+=("$line")
done < <(jq -r .user[].name <<< "$getNames")
# To print the array
printf '%s\n' "${myArray[#]}"
Just use mapfile command to read multiple lines into an array like this:
mapfile -t myArray < <(jq -r .user[].name <<< "$getNames")