Bash get value of matching substring in a long string - bash

I'm working on a bash script and having hard time extracting value from a matching substring.
I cannot share curl command as it has sensitive information but updating i value(1)(updated to mimic real value) that I'm having problem with. jq gives parse error
curl -s -g "$line" | jq -c '.allBuilds[]' | while read i; do
job_name=$(echo "$i" | jq .fullDisplayName | tr -d '»' | tr -s " " | sed 's/ /,/g' | tr -d '"')
done
expected output
Hello,Java,World,master,#47
I get expected output on most of the i values but some error out
Below are sample i values.
1
{"_class":"org.jenkinsci.plugins.workflow.job.WorkflowRun","actions":[{"_class":"hudson.model.CauseAction"},{},{"_class":"hudson.model.ParametersAction","parameters":[{"_class":"hudson.model.StringParameterValue","name":"environment","value":"DE"},{"_class":"hudson.model.BooleanParameterValue","name":"update","value":false},{"_class":"hudson.model.BooleanParameterValue","name":"black","value":false},{"_class":"hudson.model.StringParameterValue","name":"description","value":"DE"},{"_class":"hudson.model.StringParameterValue","name":"number","value":""},{"_class":"hudson.model.StringParameterValue","name":"config","value":"{ "E": "DE", "Exp": "1111", "Pr": "D", "Man": { "Se": "arn:aws:secretsmanager:region:111111111111:secret:DE/A/Se-B8SKMz", "OR": "arn:aws:secretsmanager:region:111111111111:secret:DE/A/OR-kvJ2lJ", "AR": "arn:aws:secretsmanager:region:111111111111:secret:A/DE/SA/rds", "User": "arn:aws:secretsmanager:region:111111111111:secret:DE/A/mUixbWY", "sales": "arn:aws:secretsmanager:region:111111111111:secret:DE/A/saELY", "vau": "arn:aws:secretsmanager:region:111111111111:secret:DE/A/vNRR7BO", "sc": "", "exAd": "arn:aws:secretsmanager:region:111111111111:secret:BA/A/ExyBoYL", "exp": "arn:aws:secretsmanager:region:111111111111:secret:BA/A/Exl67GE", "sec": "arn:aws:secretsmanager:region:111111111111:secret:DE/A/Secle06a", "Secu": "arn:aws:secretsmanager:region:111111111111:secret:DE/A/Seia" }, "s3": { "buckets": { "hello": { "name": "helloDEBA", "region": "region", "account": "111111111111" }, "mlt": { "name": "sacdhbd", "region": "region", "account": "111111111111" }, "devo": { "name":"devvvvv", "region": "region", "account": "5555555" } } }, "roles": { "lam": "arn:aws:iam::111111111111:role/lam", "lambd": "arn:aws:iam::111111111111:role/lambd", "la": "arn:aws:iam::111111111111:role/lam", "la": "arn:aws:iam::111111111111:role/la", "la": "arn:aws:iam::111111111111:role/la","lasds": "arn:aws:iam::111111111111:role/lafgg", "lafdg": "arn:aws:iam::111111111111:role/dfsdv", "acc": "arn:aws:iam::111111111111:role/acc" }, "vpc": { "subnets": { "private": { "1a": "subnet-111111", "1b": "subnet-22222", "1c": "subnet-33333" } }, "securityGroupIds": { "lambda": "sg-1111" }, "endpoints": { "e": "" }, "links": { "b": "" } }, "securi": { "level": "FAILURE", "s": true }, "log": "debug", "se": "hello.com", "sa": { "env": "--DE" }, "lam": { "sss": { "environment": { "variables": { "test": "hello.com", "PhoneNumber": "11111" } } } } }"},{"_class":"hudson.model.BooleanParameterValue","name":"scan","value":false},{"_class":"hudson.model.BooleanParameterValue","name":"ch","value":false}]},{"_class":"jenkins.scm.A.SCMRevisionAction"},{},{"_class":"hudson.plugins.git.util.BuildData"},{"_class":"hudson.plugins.git.GitTagAction"},{},{},{},{"_class":"org.jenkinsci.plugins.workflow.cps.EnvActionImpl"},{"_class":"hudson.plugins.git.util.BuildData"},{},{},{},{},{},{"_class":"org.jenkinsci.plugins.pipeline.modeldefinition.actions.RestartDeclarativePipelineAction"},{},{"_class":"org.jenkinsci.plugins.workflow.job.views.FlowGraphAction"},{},{},{},{}],"fullDisplayName":"Hello » Java » World » master #25","id":"25","number":25,"timestamp":1575582153372}
2
{"_class":"org.jenkinsci.plugins.workflow.job.WorkflowRun","actions":[{"_class":"hudson.model.CauseAction"},{"_class":"hudson.model.ParametersAction","parameters":[{"_class":"hudson.model.BooleanParameterValue","name":"helo-world","value":false},{"_class":"hudson.model.StringParameterValue","name":"environment","value":"hello"},{"_class":"hudson.model.StringParameterValue","name":"config","value":""},{"_class":"hudson.model.StringParameterValue","name":"description","value":""},{"_class":"hudson.model.BooleanParameterValue","name":"hello","value":false},{"_class":"hudson.model.BooleanParameterValue","name":"hello2","value":false},{"_class":"hudson.model.BooleanParameterValue","name":"scan","value":false},{"_class":"hudson.model.StringParameterValue","name":"hello3","value":""}]},{"_class":"jenkins.scm.api.SCMRevisionAction"},{},{"_class":"hudson.plugins.git.util.BuildData"},{"_class":"hudson.plugins.git.GitTagAction"},{},{},{},{"_class":"org.jenkinsci.plugins.workflow.cps.EnvActionImpl"},{"_class":"hudson.plugins.git.util.BuildData"},{},{},{},{},{},{"_class":"org.jenkinsci.plugins.pipeline.modeldefinition.actions.RestartDeclarativePipelineAction"},{},{"_class":"org.jenkinsci.plugins.workflow.job.views.FlowGraphAction"},{},{},{},{}],"fullDisplayName":"Hello»Java»World»master#21","id":"21","number":21,"timestamp":1574705384077}
I'm trying to extract fullDisplayName value and I have tried some options like
printf '%s\n' "$i" | grep fullDisplayName
printf '%s\n' gives output in new lines when tried in shell but in script its different behavior
{}
{}
{}]
fullDisplayName:Hello » Java » World » master #25
id:25
number:25
timestamp:1575582153372

It would appear that you should be using read -r.
It also appears that it would be much simpler if you focused on using curl and jq to extract the information, without any grep or tr invocation and without any shell looping. Assuming you can arrange for the output of curl to be valid JSON(*), a single invocation of jq along the following lines should do the job:
jq -c '.allBuilds[] | .fullDisplayName | gsub("»";"")'
(*) To check whether the output of curl is valid, you can pipe the output of your curl command into jq empty:
curl ... | jq empty

Related

Formating awk output to json using jq

I'm using grep to search for specific text inside multiple files.
grep -n -r "text_to_match" *
The output is:
john:15
Hana:11
After that, am using awk to print whatever meets my criteria of the condition
grep -n -r "text_to_match" * | awk -F '[:]' '{print $1,$2}'
I want now to use jq to have the following json document
{
"data": [
{
"name": "john",
"age": 15
},
{
"name": "Hana",
"age": 11
}
]
}
I tried the following:
jq -R 'split(" ") | { file:.[0], start_line:.[1]}'
Output
{
"name": "john",
"age": 15
}
{
"name": "Hana",
"age": 11
}
Thank you
As jq can also do the splitting, you could start before doing it with awk, having
john:15
Hana:11
Then, with -R you can read in the raw lines. Using -n in combination with [inputs] makes it an array. You can split using the / operator, and wrap everything in an object of your choice.
jq -Rn '{data: [inputs / ":" | {name: .[0], age: .[1]}]}'
{
"data": [
{
"name": "john",
"age": "15"
},
{
"name": "Hana",
"age": "11"
}
]
}
Demo

jq and Bash: How to get value of key from value of object? (How to build/update a json?)

First of all, sorry for my English, I'm French.
I'm working on a script, which retrieves tags and links from M3U files to store them into variables.
M3U:
#EXTM3U
#EXTINF:-1 tvg-id="TFX.fr" tvg-name="TFX" tvg-country="FR;AD;BE;LU;MC;CH" tvg-language="French" tvg-logo="http://www.exemple.com/image.jpg" group-title="",TFX (720p)
https://tfx-hls-live-ssl.tf1.fr/tfx/1/hls/live_2328.m3u8
script:
#!/bin/bash
tags='#EXTINF:-1 tvg-id="TFX.fr" tvg-name="TFX" tvg-country="FR;AD;BE;LU;MC;CH" tvg-language="French" tvg-logo="http://www.exemple.com/image.jpg" group-title="Fiction",TFX (720p)'
get_chno="$(echo "$tags" | grep -o 'tvg-chno="[^"]*' | cut -d '"' -f2)"
get_id="$(echo "$tags" | grep -o 'tvg-id="[^"]*' | cut -d '"' -f2)"
get_logo="$(echo "$tags" | grep -o 'tvg-logo="[^"]*' | cut -d '"' -f2)"
get_grp_title="$(echo "$tags" | grep -o 'group-title="[^"]*' | cut -d '"' -f2)"
get_title="$(echo "$tags" | grep -o ',[^*]*' | cut -d ',' -f2)"
get_name="$(echo "$tags" | grep -o 'tvg-name="[^"]*' | cut -d '"' -f2)"
get_country="$(echo "$tags" | grep -o 'tvg-country="[^"]*' | cut -d '"' -f2)"
get_language="$(echo "$tags" | grep -o 'tvg-language="[^"]*' | cut -d '"' -f2)"
echo -e "chno:\n $get_chno"
echo -e "id:\n $get_id"
echo -e "logo:\n $get_logo"
echo -e "grp 1:\n $get_grp_title"
echo -e "title:\n $get_title"
echo -e "name:\n $get_name"
echo -e "country:\n $get_country"
echo -e "lang:\n $get_language"
I would like to store these variables in a json file.
This json will be used to rebuild another playlist.
#EXTM3U
#EXTINF:-1 tvg-id="TFX.fr" tvg-name="TFX" tvg-country="FR;AD;BE;LU;MC;CH" tvg-language="French" tvg-logo="http://www.exemple.com/image.jpg" group-title="",TFX (720p)
https://tfx-hls-live-ssl.tf1.fr/tfx/1/hls/live_2328.m3u8
#EXTINF:-1 tvg-id="TFX.fr" tvg-name="TFX" tvg-country="FR;AD;BE;LU;MC;CH" tvg-language="French" tvg-logo="http://127.0.0.1/img/image.jpg" group-title="",TFX (local)
http://127.0.0.1:1234/tfx/live.m3u8
The file which contains multiple arrays and multiple objects.
Like this :
{
"Channels": [
{
"name": "TFX",
"old_name": "NT1",
"logo": "http://www.exemple.com/image.jpg",
"category": "Fiction",
"urls": {
"Official": [
{
"server_name": "TF1",
"IP_address": "8.8.8.8",
"url": "tfx-hls-live-ssl.tf1.fr",
"port": "",
"https_port": "443",
"path": "tfx/1/hls/",
"file_name": "live_2328",
"extension": ".m3u8",
"full_url": "https://tfx-hls-live-ssl.tf1.fr/tfx/1/hls/live_2328.m3u8"
}
],
"Xtream_Servers": [
{
"server_name": "local",
"user_name": "rickey",
"stream_id": "11",
"category_name": "Fiction",
"category_id": "12"
}
]
},
"languages": [
{
"code": "fr",
"name": "Français"
}
],
"countries": [
{
"code": "fr",
"name": "France"
},
{
"code": "be",
"name": "Belgium"
}
],
"tvg": {
"id": "TFX.fr",
"name": "TFX",
"url": ""
}
},
{
"name": "France 2",
"old_name": "",
"logo": "http://www.exemple.com/image.jpg",
"category": "Général",
"urls": {
"Official": [
{
"server_name": "France TV",
"IP_address": "8.8.8.8",
"url": "france2.fr",
"port": "",
"https_port": "443",
"path": "live/",
"file_name": "Playlist",
"extension": ".m3u8",
"full_url": "https://france2.fr/live/Playlist.m3u8"
}
],
"Xtream_Servers": [
{
"server_name": "localhost",
"user_name": "rickey",
"stream_id": "2",
"category_name": "Général",
"category_id": "10"
}
]
},
"languages": [
{
"code": "fr",
"name": "Français"
}
],
"countries": [
{
"code": "fr",
"name": "France"
},
{
"code": "be",
"name": "Belgique"
}
],
"tvg": {
"id": "France2.fr",
"name": "France 2",
"url": ""
}
},
{
"name": "M6",
"old_name": "",
"logo": "http://www.exemple.com/image.jpg",
"category": "Général",
"urls": {
"Official": [
{
"server_name": "6Play",
"IP_address": "8.8.8.8",
"url": "6play.fr",
"port": "",
"https_port": "443",
"path": "live/",
"file_name": "Playlist",
"extension": ".m3u8",
"full_url": "https://6play.fr/M6/live/Playlist.m3u8"
}
],
"Xtream_Servers": [
{
"server_name": "localhost",
"user_name": "rickey",
"stream_id": "6",
"category_name": "Général",
"category_id": "10"
}
]
},
"languages": [
{
"code": "fr",
"name": "Français"
}
],
"countries": [
{
"code": "fr",
"name": "France"
},
{
"code": "be",
"name": "Belgique"
}
],
"tvg": {
"id": "France2.fr",
"name": "France 2",
"url": ""
}
}
],
"Third_Party": {
"Xtream_Servers": [
{
"server_name": "local",
"url": "192.168.1.100",
"port": "8080",
"https_port": "8082",
"server_protocol": "http",
"rtmp_port": "12345",
"Users_list": [
{
"username": "rickey",
"password": "azerty01",
"created_at": "",
"exp_date": "",
"is_trial": "0",
"last_check": "",
"max_connections": "3",
"allowed_output_formats": [
"m3u8",
"ts",
"rtmp"
]
}
]
},
{
"server_name": "localhost",
"url": "127.0.0.1",
"port": "8080",
"https_port": "8082",
"server_protocol": "http",
"rtmp_port": "12345",
"Users_list": [
{
"username": "rickey123",
"password": "azerty321",
"created_at": "",
"exp_date": "",
"is_trial": "0",
"last_check": "",
"max_connections": "3",
"allowed_output_formats": [
"m3u8",
"ts",
"rtmp"
]
},
{
"username": "guest",
"password": "guest01",
"created_at": "",
"exp_date": "",
"is_trial": "1",
"last_check": "",
"max_connections": "1",
"allowed_output_formats": [
"ts"
]
}
]
}
]
}
}
First question: Is it a crappy json?
To add or modify this file, the script must have the entry number (I think, if you have any other ideas, I'm interested...)
cat File.json | jq '.Channels | to_entries[]'
output:
{
"key": 0,
"value": {
"name": "TFX",
"old_name": "NT1",
2nd question:
How to get value key (0 is this case) with the value of "name", for store into variable after ? (to avoid duplicates)
key_="$(cat file.json | jq ????????? search="name": "$get_name" ???? .key)"
echo $key_
"0"
key_2="$(cat file.json | jq ????????? search="name": "$get_url" ???? .key)"
echo $key_2
"0"
if [[ $key_ == $key_2 ]]; then
Chan_Name="$(cat $1 | jq '.Channels[$key_].name)"
Echo $Chan_Name
"TFX"
jq '.[] ????? += {???? , ??? }' file.json | sponge file.json
fi
last question (most important):
How to find and modify these f*** objects, when the script does not know any values of the keys of the objects / arrays ?!
I've been looking for 2 days, my brain is liquid.
Thank you. :)
Edit 1 :
I've found a partial solution to replace value:
{
"name": "TFX",
"old_name": "NT1",
"logo": "http://www.exemple.com/image.jpg",
"category": "Fiction",
with:
cat file.json | jq -C '(.Channels[] | select(.name=="TFX").category="test")'
output:
{
"name": "TFX",
"old_name": "NT1",
"logo": "http://www.exemple.com/image.jpg",
"category": "test",
"urls": {
but "{"Channels": [" is missing. :/
jq -C '(.Channels[] | select(.name=="TFX").category="test")'
You were so close - just one misplaced parenthesis:
jq '(.Channels[] | select(.name=="TFX")) .category="test"'

Find fields which contains a text and replace it with another text

In the JSON example below how to find all the elements which contain string "Choice" and replace them with another string, for example "Grade".
So with below all the fields name "***Choice" should change to "***Grade".
I have pasted the expected output below. Given that I don't know how many fields will have the string "Choice", I don't want to simply do [$in ~> | ** [firstChoice] | {"firstGrade": firstChoice}, ["firstChoice"] | ;] which is a straight find and replace.
{
"data": {
"resourceType": "Bundle",
"id": "e919c820-71b9-4e4b-a1c8-c2fef62ea911",
"firstChoice": "xxx",
"type": "collection",
"entry": [
{
"resource": {
"resourceType": "Condition",
"id": "SMART-Condition-342",
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "38341003",
"display": "Essential hypertension",
"firstChoice": "xxx"
}
],
"text": "Essential hypertension"
},
"clinicalStatus": "active",
"secondChoice": "xxx"
},
"search": {
"mode": "match"
}
}
]
}
}
Expected output
{
"data": {
"resourceType": "Bundle",
"id": "e919c820-71b9-4e4b-a1c8-c2fef62ea911",
"firstGrade": "xxx",
"type": "collection",
"entry": [
{
"resource": {
"resourceType": "Condition",
"id": "SMART-Condition-342",
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "38341003",
"display": "Essential hypertension",
"firstGrade": "xxx"
}
],
"text": "Essential hypertension"
},
"clinicalStatus": "active",
"secondGrade": "xxx"
},
"search": {
"mode": "match"
}
}
]
}
}
There might be simpler ways, but this is an expression I came up with in JSONata:
(
$prefixes := $keys(**)[$ ~> /Choice$/].$substringBefore('Choice');
$reduce($prefixes, function($acc, $prefix) {(
$choice := $prefix & "Choice";
$acc ~> | ** [$lookup($choice)] | {$prefix & "Grade": $lookup($choice)}, [$choice] |
)}, $$)
)
It looks terrible, but I'll explain how I built it up anyway.
You started with the expression
$ ~> | ** [firstChoice] | {"firstGrade": firstChoice}, ["firstChoice"] |
which is fine if you only want to replace one choice, and you know the full name. If you want to replace more than one, then you can chain these together as follows:
$ ~> | ** [firstChoice] | {"firstGrade": firstChoice}, ["firstChoice"] |
~> | ** [secondChoice] | {"secondGrade": secondChoice}, ["secondChoice"] |
~> | ** [thirdChoice] | {"thirdGrade": thirdChoice}, ["thirdChoice"] |
At this point, you could create a higher-order function that takes the choice prefix and returns a partial substitution (note that the |...|...| syntax generates a function). Then you can chain these together for an array of prefixes using the built in $reduce() higher-order function. So you get something like this:
(
$prefixes := ["first", "second", "third"];
$reduce($prefixes, function($acc, $prefix) {(
$choice := $prefix & "Choice";
$acc ~> | ** [$lookup($choice)] | {$prefix & "Grade": $lookup($choice)}, [$choice] |
)}, $$)
)
But if you don't know the set of prefixes up front, and want to select, say, all property names that end in 'Choice', the the following expression will get you that:
$prefixes := $keys(**)[$ ~> /Choice$/].$substringBefore('Choice')
Which then arrives at my final expression. You can experiment with it here in the exerciser on your data.
I know it was 2019, but here's an alternative solution to help future readers.
$replace($string(),/([first|second|third])Choice/,"$1Grade")~>$eval()

unable to parse json into csv using jq

I have a JSON file that I want to convert into a CSV file using the jq in a shell script. I want to create a single row from this entire JSON file. I have to extract value from values. The row output should be something like
null,642,642,412,0,null,null
Here is my JSON file
{
"data": [
{
"name": "exits",
"period": "lifetime",
"values": [
{
"value": {}
}
],
"title": "Exits",
"description": "Number of times someone exited the carousel"
},
{
"name": "impressions",
"period": "lifetime",
"values": [
{
"value": 642
}
],
"title": "Impressions",
"description": "Total number of times the media object has been seen"
},
{
"name": "reach",
"period": "lifetime",
"values": [
{
"value": 412
}
],
"title": "Reach",
"description": "Total number of unique accounts that have seen the media object"
},
{
"name": "replies",
"period": "lifetime",
"values": [
{
"value": 0
}
],
"title": "Replies",
"description": "Total number of replies to the carousel"
},
{
"name": "taps_forward",
"period": "lifetime",
"values": [
{
"value": {}
}
],
"title": "Taps Forward",
"description": "Total number of taps to see this story's next photo or video"
},
{
"name": "taps_back",
"period": "lifetime",
"values": [
{
"value": {}
}
],
"title": "Taps Back",
"description": "Total number of taps to see this story's previous photo or video"
}
]
}
Hi tried using this jq command :
.data | map(.values[].value) | #csv
This is giving the following output:
jq: error (at :70): object ({}) is not valid in a csv row
exit status 5
So when I am getting this empty JSON object it is reflecting an error.
Please Help!!
The row output should be something like
null,642,642,412,0,null,null
Using length==0 here is dubious at best. To check for {} one could write:
jq '.data | map(.values[].value | if . == {} then "null" else . end) | #csv'
Similarly for [].
If you run the command without the #csv part you will see that the output is:
[
{},
642,
412,
0,
{},
{}
]
By replacing the empty objects with "null": (length == 0)
jq '.data | map(.values[].value) | map(if (type == "object" and length == 0 ) then "null" else . end) | #csv'
Output:
"\"null\",642,412,0,\"null\",\"null\""
Per suggestion from #aaron (see comment). The following can produce the requested output without extra post-processing. Disclaimer: this is not working with my jq 1.5, but working on jqplay with jq 1.6.
jq --raw-output '.data | map(.values[].value) | map(if (type == "object" and length == 0 ) then "null" else . end) | join(",")'
Output:
null,642,412,0,null,null

Replace an attribute or key in JSON using jq or sed

Have a big json like this
"envConfig": {
"environmentName": {
"versions": [
{
"name": "version1",
"value": "Dev"
},
{
"name": "version2",
"host": "qa"
}
],
"userRoles": [
{
"name": "Roles",
"entry": [
{
"name": "employees",
"value": "rwx"
},
{
"name": "customers",
"value": "rx"
}
]
}
]
}
},
I wanted to change the JSON attribute from "environmentName" to "prod". Below is the output i am expecting
"envConfig": {
"prod": {
"versions": [
...
],
"userRoles": [
...
]
}
}
Tried with sed command as below
sed "s/\('environmentName':\)/\1\"prod\"\,/g" version.json
Tried with jq as below but not working
cat version.json | jq ' with_entries(.value |= {"prod" : .environmentName} ) '
Any help here to replace the attribute/key of an json with desired value
You weren't too far off with the jq, how about this?
jq '.envConfig |= with_entries(.key |= sub("^environmentName$"; "prod"))'
Two differences: first off, we want to drill down to envConfig before doing a with_entries, and second, when we get there, the thing we want will be a key, not a value. In case there are any other keys besides environmentName they'll be preserved.
TL,TR
You can use the following command:
jq '(.envConfig |= (. + {"prod":.environmentName}|del(.environmentName)))' foo.json
Let's say you have the following json:
{
"foo": {
"hello" : "world"
}
}
You can rename the node foo to bar by first duplicating it and then remove the original node:
jq '. + {"bar":.foo}|del(.foo)' foo.json
Output:
{
"bar": {
"hello" : "world"
}
}
It get's a bit more complicated if you want to replace a child key somewhere in the tree. Let's say you have the following json:
{
"test": {
"foo": {
"hello": "world"
}
}
}
You can use the following jq command for that:
jq '(.test |= (. + {"bar":.foo}|del(.foo)))' foo.json
Note the additional parentheses and the use of the assignment operator |=.
Output:
{
"test": {
"bar": {
"hello": "world"
}
}
}
Using sed:
sed -i '/^ \"environmentName\":/ s/environmentName/prod/' <yourfile>
Keep in mind that -i will overwrite the file. You may want to make a backup first.

Resources