Expanding variables before bash call/exec - bash

I know the basics of Bash but often miss the nuance and I'm having a problem using it to achieve what I had hoped would be a rather simple problem:
If I have the following in a bash script, which works exactly as I'd want it to:
cbType=`echo $configuration | jsawk -a 'return _.where(this,{name: "reference_data"})'`
It takes $configuration -- which is a JSON string -- and identifies the array element where name is "reference_data" and returns that object/hash definition only. Please note that this does use the very handy jsawk utility but it has been designed to be exhibit good command-line behaviour.
The problem is that when I remove the hard-coded "reference-data" with a variable it seems to not be able to reference the scope of the variable. So for instance, ...
myVar="\"reference_data\""
cbType=`echo $configuration | jsawk -a 'return _.where(this,{name: $myVar})'`
Does not work and instead returns a jsawk error of:
jsawk: js error: ReferenceError: $myVar is not defined
Is there anything I can do to enforce that first the variable is expanded, and then the command string is executed?

Declared variables won't be expanded if it's not within double quotes. So put your code inside double quotes instead of single quotes.
myVar="\"reference_data\""
cbType=$(echo "$configuration" | jsawk -a "return _.where(this,{name: $myVar})")

Related

Append bash parameters and pass forward to other script

I need to pass further original parameters and also I want to add some others. Something like this:
#!/bin/bash
params="-D FOREGROUND"
params+=" -c Include conf/dev.conf"
/usr/local/apache/bin/apachectl $params "$#"
This code above don't work as expected if params contains of two or more parameters, it treated as one parameter.
The code in your example should work if the following command is valid when executed at the command line written exactly like this :
/usr/local/apache/bin/apachectl -D FOREGROUND -c Include conf/dev.conf "$#"
A quick web search leads me to think that what you want is this (notice the additional double quotes) :
/usr/local/apache/bin/apachectl -D FOREGROUND -c "Include conf/dev.conf" "$#"
Here is how to achieve that simply and reliably with arrays, in a way that sidesteps "quoting inside quotes" issues:
#!/bin/bash
declare -a params=()
params+=(-D FOREGROUND)
params+=(-c "Include conf/dev.conf")
/usr/local/apache/bin/apachectl "${params[#]}" "$#"
The params array contains 4 strings ("-D", "FOREGROUND", "-c" and "Include conf/dev/conf"). The array expansion ("${params[#]}", note that the double quotes are important here) expands them to these 4 strings, as if you had written them with double quotes around them (i.e. without further word splitting).
Using arrays with this kind of expansion is a flexible and reliable to way to build commands and then execute them with a simple expansion.
If the issue is the space in the parameter "-c Include conf/dev.conf" then you could just use a backspace to preserve the space character:
params+="-c Include\ conf/dev.conf"

Variable interpolation in the shell

I have a variable called filepath=/tmp/name.
To access the variable, I know that I can do this: $filepath
In my shell script I attempted to do something like this (the backticks are intended)
`tail -1 $filepath_newstap.sh`
This line fails, duuh!, because the variable is not called $filepath_newstap.sh
How do I append _newstap.sh to the variable name?
Please note that backticks are intended for the expression evaluation.
Use
"$filepath"_newstap.sh
or
${filepath}_newstap.sh
or
$filepath\_newstap.sh
_ is a valid character in identifiers. Dot is not, so the shell tried to interpolate $filepath_newstap.
You can use set -u to make the shell exit with an error when you reference an undefined variable.
Use curly braces around the variable name:
`tail -1 ${filepath}_newstap.sh`
In Bash:
tail -1 ${filepath}_newstap.sh

Substitute a bash script variable twice

I would like to know if I can substitute a variable twice.
For example:
#global variable
TEST_SERV_EXT=""
#variables become from myconf.sh
TEST_SERV_EXT_FO='foo01'
TEST_SERV_EXT_BR='bar01'
I want dynamically construct those last two and assign them in TEST_SERV_EXT.
I tried something like this ${$TEST_SERV_COMP} but I'm getting "bad substitution" message.
I need something like php's feature "$$" or tcl's subst command.
Regards,
thandem
TEST_SERV_COMP=TEST_SERV_EXT_FO
TEST_SERV_EXT=${!TEST_SERV_COMP}
Look for indirect expansion in the bash manual.

variable substitution removing quotes

I seem to have some difficulty getting what I want to work. Basically, I have a series of variables that are assigned strings with some quotes and \ characters. I want to remove the quotes to embed them inside a json doc, since json hates quotes using python dump methods.
I figured it would be easy. Just determine how to remove the characters easy and then write a simple for loop for the variable substitution, well it didn't work that way.
Here is what I want to do.
There is a variable called "MESSAGE23", it contains the following "com.centrify.tokend.cac", I want to strip out the quotes, which to me is easy, a simple echo $opt | sed "s/\"//g". When I do this from the command line:
$> MESSAGE23="com."apple".cacng.tokend is present"
$> MESSAGE23=`echo $MESSAGE23 | sed "s/\"//g"`
$> com.apple.cacng.tokend is present
This works. I get the properly formatted string.
When I then try to throw this into a loop, all hell breaks loose.
for i to {1..25}; do
MESSAGE$i=`echo $MESSAGE$i | sed "s/\"//g"`
done
This doesn't work (either it throws a bunch of indexes out or nothing), and I'm pretty sure I just don't know enough about arg or eval or other bash substitution variables.
But basically I want to do this for another set of variables with the same problems, where I strip out the quotes and incidentally the "\" too.
Any help would be greatly appreciated.
You can't do that. You could make it work using eval, but that introduces another level of quoting you have to worry about. Is there some reason you can't use an array?
MESSAGE=("this is MESSAGE[0]" "this is MESSAGE[1]")
MESSAGE[2]="I can add more, too!"
for (( i=0; i<${#MESSAGE[#]}; ++i )); do
echo "${MESSAGE[i]}"
done
Otherwise you need something like this:
eval 'echo "$MESSAGE'"$i"'"'
and it just gets worse from there.
First, a couple of preliminary problems: MESSAGE23="com."apple".cacng.tokend is present" will not embed double-quotes in the variable value, use MESSAGE23="com.\"apple\".cacng.tokend is present" or MESSAGE23='com."apple".cacng.tokend is present' instead. Second, you should almost always put double-quotes around variable expansions (e.g. echo "$MESSAGE23") to prevent parsing oddities.
Now, the real problems: the shell doesn't allow variable substitution on the left side of an assignment (i.e. MESSAGE$i=something won't work). Fortunately, it does allow this in a declare statement, so you can use that instead. Also, when the sees $MESSAGE$i it replaces it will the value of $MESSAGE followed by the value of $i; for this you need to use indirect expansion (`${!metavariable}').
for i in {1..25}; do
varname="MESSAGE$i"
declare $varname="$(echo "${!varname}" | tr -d '"')"
done
(Note that I also used tr instead of sed, but that's just my personal preference.)
(Also, note that #Mark Reed's suggestion of an array is really the better way to do this sort of thing.)

Environment variable within variable

I have an environment variable called $TEST which refers to a directory
in my bash script I have a variable called $VARTEST which is $TEST/dir/file
now I want to grep the file specified by $VARTEST so I try to do:
grep somestring $VARTEST but it doesn't translate $TEST into it's directory
I've tried different combinations of {}, "" and '' but without success
I think you want
eval grep somestring "$VARTEST"
or even
VARTEST_EVALUATED=$(eval echo $VARTEST)
grep "$SOMESTRING" "$VARTEST_EVALUATED"
but remember (as others already said): If possible use
VARTEST="$TEST/foo/bar"
instead of
VARTEST='$TEST/foo/bar'
use the second one only if you really need kind of 'lazy evaluation'...
Warning, this could be dangerous if $VARTEST contains malicous code.
Have you put single quotes around something? Single quotes will prevent the variables from being translated into their corresponding values. Double quotes will work though. For example:
#!/bin/sh
TEST="/etc"
VARTEST="$TEST/passwd"
grep "$LOGNAME" "$VARTEST"

Resources