Filter on nested array with jmespath (using az cli) - azure-cli

I would like to know if a value in a TXT record is already available in the DNS:
az network dns record-set txt show -g myresourcegroup -z 'mydomain' -n 'mytxtvalues'
This is the part of the json result where it's all about:
"txtRecords": [
{
"value": [
"abc"
]
},
{
"value": [
"def"
]
}
]
I tried many queries. These are 2 which I expected to work.
az network dns record-set txt show -g myresourcegroup -z 'mydomain.com' -n 'mytxtvalues' --query txtRecords[?value[?starts_with(#, 'abc')]]
az network dns record-set txt show -g myresourcegroup -z 'mydomain.com' -n 'mytxtvalues' --query txtRecords[*].value[?starts_with(#, 'abc')]]
The result is:
At line:1 char:123
+ ... 'mytxtvalues' --query txtRecords[?value[?starts_with(#, 'abc') ...
+ ~ Unrecognized token in source text. At line:1 char:124
+ ... 'mytxtvalues' --query txtRecords[?value[?starts_with(#, 'abc')] ...
+ ~ Missing argument in parameter list.
It looks like the # used to filter the array is not recognized. But I don't know how to query otherwise.
What would be a correct query to know if value abc is already in the list?

You need to use the command like this:
az network dns record-set txt show -g myresourcegroup -z 'mydomain.com' -n 'mytxtvalues' --query "txtRecords[*].value[?starts_with(#, 'abc')]"
And if you just need to output the string you can append the parameter -o tsv. Hope this will help you.

Related

Create Bash loop from JSON string using jq

I am writing a bash script that reads a JSON string then loop based on the JSON values to execute a CLI command.
#!/usr/bin/env bash
jq --version > /dev/null 2>&1 || { echo >&2 "jq is required but it's not installed. Aborting."; exit 1; }
read -r -d '' USER_ACTIONS << EOM
{
"user1": [
"action1"
],
"user2": [
"action2",
"action3"
]
}
EOM
USERS= #TODO
for user in USERS; do
ACTIONS= #TODO
for action in ACTIONS; do
echo "Executing ${command} ${user}-${action}"
done
done
If jq is present in the server, how do I populate the USERS and ACTIONS variable?
Depending on what command you want to execute, if it can be performed from within jq, it's easier to also move the loop inside. There are several ways to accomplish that. Here are some examples, all yielding the same output:
jq -r 'to_entries[] | "Executing command \(.key)-\(.value[])"' <<< "$USER_ACTIONS"
jq -r 'keys[] as $user | "Executing command \($user)-\(.[$user][])"' <<< "$USER_ACTIONS"
jq -r --stream '"Executing command \(.[0][0])-\(.[1]? // empty)"' <<< "$USER_ACTIONS"
Output:
Executing command user1-action1
Executing command user2-action2
Executing command user2-action3
It seems better to play with vanilla js (nodejs):
const myvar={
"user1": [
"action1"
],
"user2": [
"action2",
"action3"
]
};
for (let user in myvar) {
myvar[user].forEach((action) => {
console.log("Executing command " + user + "-" + action);
});
}
Output
Executing command user1-action1
Executing command user2-action2
Executing command user2-action3
Usage
node script.js
Usage with bash
You can remove Executing string, then:
node script.js | bash
Would you please try the following:
#!/bin/bash
declare -a users # array of users
declare -A actions # array of actions indexed by user
read -r -d '' user_actions << EOM
{
"user1": [
"action1"
],
"user2": [
"action2",
"action3"
]
}
EOM
while IFS=$'\t' read -r key val; do
users+=( "$key" ) # add the user to the array "users"
actions[$key]="$val" # associate the actions with the user
done < <(jq -r 'to_entries[] | [.key, .value[]] | #tsv' <<< "$user_actions")
for user in "${users[#]}"; do # loop over "users"
IFS=$'\t' read -r -a vals <<< "${actions[$user]}"
for action in "${vals[#]}"; do
echo yourcommand "$user" "$action"
done
done
Output:
yourcommand user1 action1
yourcommand user2 action2
yourcommand user2 action3
[Explanations]
The jq command outputs TSV which looks like:
user1\taction1
user2\taction2\taction3
where \t represents a tab character used as a field delimiter.
The first read builtin command assigns key to the first field and val
to the remaining field(s). If val contains two or more fields,
it will be splitted with tne next read builtin in the next loop.
if the output looks good, drop echo and replace the string yourcommand with the command name.

How to store json key value pair in and store it in one variable in linux

I am calling python command which will return data is JSON key-value pair.
I have put python command and other command in one shell script named as - a.sh
Code (a.sh):
cd /home/drg/Code/dth
a=$(python3 main.py -z shell -y droub -i 56)
echo "$a"
When I am calling this script I am getting output as:
{'password': 'XYZ', 'name': 'Stguy', 'port': '5412', 'host': 'igtet', 'db_name': 'test3'}
And after getting this output I want to pass the output value like password, name to psql command to run postgresql query.
So, what I want is that I should be able to store password value in one variable, name in one variable like:
a= xyz
b=Stguy
p= port
So, that I can use this variables to pass in psql query as:
psql -h $a -p $p -U $b -d $db -c "CREATE SCHEMA IF NOT EXISTS ${sname,,};"
Can someone please help me with this?
Note: Env is linux(Centos 8)
Thanks in advance!
One way of solving this could be a combination of jq for value extraction and shell-builtin read for multiple variable assignment:
JSON='{"name": "Stguy", "port": 5412, "host": "igtet", "db_name": "test3"}'
read -r a b c <<<$( echo $JSON | jq -r '"\(.host) \(.port) \(.name)"' )
echo "a: $a, b: $b, c: $c"
doing jq string interpolation "\( )" to print result in one line
You can aslo go with sed or awk:
PSQL="$( python3 main.py -z shell -y droub -i 56 | sed "s/^[^:]*: *'\([^']*\)'[^:]*: *'\([^']*\)'[^:]*: *'\([^']*\)'[^:]*: *'\([^']*\)'[^:]*: *'\([^']*\)'}/psql -h '\4' -p '\1' -U '\2' -d '\5'/")"
[ "${PSQL:0:5}" = "psql " ] && ${PSQL} -c "CREATE SCHEMA IF NOT EXISTS ${sname,,};"
For security consideration, i urge you anyway to avoid passing account data (user passwd) through environment variables.
It would be better if your python script had an option to directly launch psql with required parameters.

extract variable from json style output in Linux command

I try to use the AWS secrets manager in the linux system. I could use aws cli command
aws secretsmanager get-secret-value --secret-id abc_account --version-stage AWSCURRENT
to get following output
{
"ARN": "arn:aws:secretsmanager:us-east-1:123456789:secret:abc_account-XhteiW",
"Name": "abc_account",
"VersionId": "89637ef4-4594-4c63-9887-3f7d2c7ccc6f",
"SecretString": "{\"username\":\"abc_account\",\"password\":\"PASSWORD111\"}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2021-02-08T23:57:58.325000-05:00"
}
what I need is to save the password PASSWORD111 into a variable var1 in the linux. something like
var1=$(aws secretsmanager get-secret-value --secret-id svc_vma_insights_data_platform --version-stage AWSCURRENT | awk XXXXXX )
or
var1=$(aws secretsmanager get-secret-value --secret-id svc_vma_insights_data_platform --version-stage AWSCURRENT | grep XXXXXX )
This is extracting the secret string from the JSON output, and then extracting the password from that JSON:
passwd=$(aws ... | jq -r '.SecretString' | jq -r '.password')
On linux you may try this gnu grep:
var1=$(aws ... | grep -oP 'password\W+\K[^"\\]+')
echo "$var1"
PASSWORD111
Command regex:
password\W+: Match text password followed by 1+ non-word characters
\K: Reset match info
[^"\\]+: Match 1+ of any character that is not a " and not a \

How to az group list using ubuntu bash foreach json array name value

azure cli az group list return data like
[
"demo3",
"demo",
"demo2",
"NetworkWatcherRG"
]
I'd like to foreach it's value on ubuntu bash then printing below result
demo3
demo
demo2
NetworkWatcherRG
What I've tried :
I tried below script
jq -c '.[]' $(az group list) | while read i; do echo $i ;done
but get image's error
Your command expands to this (see it for yourself with set -x):
jq -c '.[]' '[' '"demo3",' '"demo",' '"demo2",' '"NetworkWatcherRG"' ']'
The command substitution is replaced with the command output, but jq doesn't expect a JSON body as a parameter – either files containing JSON, or a stream in standard input. Since all the parameters ([, "demo3" etc.) are not filenames, you see the errors you do.
You could have Bash make it look like it's a file with process substitution:
jq -c '.[]' <(az group list)
or, more portably, use pipes:
az group list | jq -c '.[]'
Notice that quoting wouldn't help here either: if you ran
jq -c '.[] "$(az group list)"
it would expand to
jq -c '.[]' '[
"demo3",
"demo",
"demo2",
"NetworkWatcherRG"
]'
and jq would try to open a file with the name
[
"demo3",
"demo",
"demo2",
"NetworkWatcherRG"
]
which does not exist.

passing json array with spaces to bash script for az cli tagging

I have a bash script that looks like the following and correctly passes tags to the az cli that includes spaces.
RESOURCE_GROUP_NAME=$1
LOCATION=$2
TAGS_INPUT_ARGUMENT=$3 # This TAGS_INPUT_ARGUMENT needs to finally look like the TAGS below.
echo 'TAGS_INPUT_ARGUMENT:' $TAGS_INPUT_ARGUMENT
# HARD CODED TAGS that Work
TAGS=("owner=Firstname Lastname" "application=cool-name")
echo 'TAGS:' "${TAGS[#]}"
az group create \
--name $RESOURCE_GROUP_NAME \
--location $LOCATION \
--tags "${TAGS[#]}"
I am having problems passing the TAGS into the script.
i.e.
export TAGS='["owner=Firstname Lastname","application=cool-name"]'
bash ./entrypoint.sh rg-lionking eastus2 "${TAGS}"
Output:
TAGS_INPUT_ARGUMENT: ["owner=Firstname Lastname","application=cool-name"]
TAGS: owner=Firstname Lastname application=cool-name
{
"id": "/subscriptions/**REDACTED**/resourceGroups/rg-lionking",
"location": "eastus2",
"managedBy": null,
"name": "rg-lionking",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {
"application": "cool-name",
"owner": "Firstname Lastname"
},
"type": "Microsoft.Resources/resourceGroups"
}
Given that I can get TAGS in a good state, what do I need to do to pass in the same thing in json format and get it working as the final argument to the az group create cli?
My jp knowledge is practically zero, so I am guessing that the answer lies in there somewhere.
The equivalent to expanding an array is on the command line is passing multiple separate arguments
./entrypoint rg-lionking eastus2 "owner=Firstname Lastname" "application=cool-name"
...and then, in entrypoint:
#!/usr/bin/env bash
resource_group_name=$1; shift
location=$1; shift
tags=( "$#" )
az group create \
--name "$resource_group_name" \
--location "$location" \
--tags "${tags[#]}"