How to use environment variable parameter in jq parsing - bash

In the following bash code, I'm getting null as value instead of actual value. I'm using jq 1.5 in Linux OS.
getProperty(){
export PROP=$1
export value_found=`cat my.json | jq '."env.PROP"'`
echo "$1 = $value_found"
}
getProperty "first.name"
getProperty "last.name"
Contents of my.json
{"first.name":"Adam", "last.name":"Eve"}
My program requires to get value for properties selected randomly, so the property name is not known before runtime (hence the reason for trying to use parameters)

Your idea is right, but you don't need to export the variables/use the environment variables here. Just pass in the arguments and use the internal jq logic to import variables from shell.
The key here is to access arguments containing ., wrap them over []
getProperty(){
jq --arg namearg "$1" '.[$namearg]' < json
}
and now call with the args as needed
getProperty "first.name"
"Adam"
getProperty "last.name"
"Eve"

Related

How can I source Terraform HCL variables in bash?

I have Terraform variables defined like
variable "location" {
type = string
default = "eastus"
description = "Desired Azure Region"
}
variable "resource_group" {
type = string
default = "my-rg"
description = "Desired Azure Resource Group Name"
}
and potentially / partially overwritten in terraform.tfvars file
location = "westeurope"
and then defined variables as outputs e.g. a file outputs.tf:
output "resource_group" {
value = var.resource_group
}
output "location" {
value = var.location
}
How can I "source" the effective variable values in a bash script to work with these values?
One way is to use Terraform output values as JSON and then an utility like jq to convert and source as variables:
source <(terraform output --json | jq -r 'keys[] as $k | "\($k|ascii_upcase)=\(.[$k] | .value)"')
note that output is only available after executing terraform plan, terraform apply or even a terraform refresh
If jq is not available or not desired, sed can be used to convert Terraform HCL output into variables, even with upper case variable names:
source <(terraform output | sed -r 's/^([a-z_]+)\s+=\s+(.*)$/\U\1=\L\2/')
or using -chdir argument if Terraform templates / modules are in another folder:
source <(terraform -chdir=$TARGET_INFRA_FOLDER output | sed -r 's/^([a-z_]+)\s+=\s+(.*)$/\U\1=\L\2/')
Then these variables are available in bash script:
LOCATION="westeurope"
RESOURCE_GROUP="my-rg"
and can be addressed as $LOCATION and $RESOURCE_GROUP.

Assign the return of two piped functions in bash to a variable

I make a get request to a public API via the unix shell. Then I select a specific string value pair. This works perfectly, however I am unable to assign it to a variable called max_temperature.
Can someone help?
response="$(curl $url)"
max_temperature=$response | jq '.["main"].temp_max'
The line
max_temperature=$response | jq '.["main"].temp_max'
will cause the max_temparature var to be set to the contents of $response and pipe the output of this statement (in this case no output) to jq.
What you probably want is:
max_temperature=$(echo $response | jq '.["main"].temp_max')
This spawns a subshell and executes
echo $response | jq '.["main"].temp_max'
in it.
However, since a subshell does not take its parents environment with it by default, $response will be empty when it is echoed. You will need to export it in the line before. Hence:
response="$(curl $url)"
export response
max_temperature=$(echo $response | jq '.["main"].temp_max')
More on Command substitution

how to call a bash function providing environment variables stored in a Bash array?

I got two variables in a bash script. One contains the name of a function within the script while the other one is an array containing KEY=VALUE or KEY='VALUE WITH SPACES' pairs. They are the result of parsing a specific file, and I can't change this.
What I want to do is to invoke the function whose name I got. This is quite simple:
# get the value for the function
myfunc="some_function"
# invoke the function whose name is stored in $myfunc
$myfunc
Consider the function foo be defined as
function foo
{
echo "MYVAR: $MYVAR"
echo "MYVAR2: $MYVAR2"
}
If I get the variables
funcname="foo"
declare -a funcenv=(MYVAR=test "MYVAR2='test2 test3'")
How would I use them to call foo with the pairs of funcenv being added to the environment? A (non-variable) invocation would look like
MYVAR=test MYVAR2='tes2 test3' foo
I tried to script it like
"${funcenv[#]}" "$funcname"
But this leads to an error (MYVAR=test: command not found).
How do I properly call the function with the arguments of the array put in its environment (I do not want to export them, they should just be available for the invoked function)?
You can do like this:
declare -a funcenv=(MYVAR=test "MYVAR2='test2 test3'")
for pairs in "${funcenv[#]}"; do
eval "$pairs"
done
"$funcname"
Note however that the variables will be visible outside the function too.
If you want to avoid that, then you can wrap all the above in a (...) subshell.
why don't you pass them as arguments to your function?
function f() { echo "first: $1"; echo "second: $2"; }
fn=f; $fn oneword "two words"

How to make a script read a value from a property file and pass it to the same script?

I am new to linux shell script. i want that my script read a property file and save the value in any variable , the same which i can pass in same script..
as i wrote script is not fulfilling my requirement:
!/bin/bash
. test1
flat
if [ "$1" == test1 ]; then
flat=$1; /assign value to var flat
echo "flat"
fi
test1 is property file which includes :
la=12
tu=15
now i want when i run:
./myscript la
it read it from property file and store the value in flat variable.
Please help me.
You just need to use indirect referencing, but to do so, you need to store the value of the special parameter $1 in a regular parameter first.
!/bin/bash
. test1
var="$1"
# Only assign to flat if the variable specified in var is defined
if [ -n "${!var:-}" ]; then
flat="${!var}"; # assign value to var flat
echo "flat"
fi
First, ${!var} expands to the value of the variable whose name is in var. If var is "foo", it's the same as $foo. If var is "baz", it's the same as $baz.
${var:-default} expands to the value of var if it is set and has a non-null value. Otherwise, it expands to whatever you have after the ':-', in this case the string default. If there is no string, it uses the null value. So ${var:-} would expand to the null string if var was not set (or was already the null string).
Combining the two, ${!var:-} takes the variable var, and uses its value as a variable name. It then tries to expand that variable, and if it isn't set or is null, expand to the null string. So if var is la, it expands to the value of la. If var is re, and there is no variable re set, it expands to the null string.
Finally, the -n operator tests if its argument is non-zero length. In other words, it checks that the result of trying to expand the variable whose name is in var is not the null string. If that's true, then expand it again (yes, it's a little redundant) and assign its value to flat.
As the answer is written above, the variable flat is undefined if the argument to the script is not the name of a variable set in test1. If you don't mind flat being set regardless (say, flat=""), you don't need the if statement. You can just use one line to set the value of flat:
#!/bin/bash
. test1
var="$1"
flat="${!var:-}"
If I understood correctly you want to achieve an indirect variable dereferencing (see e.g. this example).
The solution is to use eval:
eval flat=\$$1

Create variable from string/nameonly parameter to extract data in bash?

I want to save the variable name and its contents easily from my script.
Currently :-
LOGFILE=/root/log.txt
TEST=/file/path
echo "TEST : ${TEST}" >> ${LOGFILE}
Desired :-
LOGFILE=/root/log.txt
function save()
{
echo "$1 : $1" >> ${LOGFILE}
}
TEST=/file/path
save TEST
Obviously the above save function just saves TEST : TEST
Want I want it to save is TEST : /file/path
Can this be done? How? Many thanks in advance!
You want to use Variable Indirection. Also, don't use the function keyword, it is not POSIX and also not necessary as long as you have () at the end of your function name.
LOGFILE=/root/log.txt
save()
{
echo "$1 : ${!1}" >> ${LOGFILE}
}
TEST=/file/path
save TEST
Proof of Concept
$ TEST=foo; save(){ echo "$1 : ${!1}"; }; save TEST
TEST : foo
Yes, using indirect expansion:
echo "$1 : ${!1}"
Quoting from Bash reference manual:
The basic form of parameter expansion is ${parameter} [...] If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion
Consider using the printenv function. It does exactly what it says on the tin, prints your environment. It can also take parameters
$ printenv
SSH_AGENT_PID=2068
TERM=xterm
SHELL=/bin/bash
LANG=en_US.UTF-8
HISTCONTROL=ignoreboth
...etc
You could do printenv and then grep for any vars you know you have defined and be done in two lines, such as:
$printenv | grep "VARNAME1\|VARNAME2"
VARNAME1=foo
VARNAME2=bar

Resources