Environment variable within variable - bash

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"

Related

Contact multiple variable with string bash

This is my script code
#!/bin/bash
timestamp=$(date +%F-%T)
clinet_id="123"
STRING=s3://<bucketname>/folder/$client_id/$client_id_gdpr_access_report_$timestamp.csv
echo "$STRING"
$SHELL
If i run this code am getting timestamp value.csv file
how can i concatenate variable with string.
am expecting out put like below
s3://<bucketname>/folder/123/123_report_2022-01-25-14:55:47.csv
i can able to concatenateaccess_report_$timestamp.csv
if i add $client_id_ in the beginning, it will print
2022-01-25-14:55:47.csv
Expecting a better advice
You need to look better at the names of your variables; it's 'client_id' not 'clinet_id' ...
And you should take care of double quoting your string, and put braces around variables when in doubt:
STRING="s3://<bucketname>/folder/${client_id}/${client_id}_gdpr_access_report_${timestamp}.csv"

Expanding variables before bash call/exec

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})")

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.)

Bash script execute shell command with Bash variable as argument

I have one loop that creates a group of variables like DISK1, DISK2... where the number at the end of the variable name gets created by the loop and then loaded with a path to a device name. Now I want to use those variables in another loop to execute a shell command, but the variable doesn't give its contents to the shell command.
for (( counter=1 ; counter<=devcount ; counter++))
do
TEMP="\$DISK$counter"
# $TEMP should hold the variable name of the disk, which holds the device name
# TEMP was only for testing, but still has same problem as $DISK$counter
eval echo $TEMP #This echos correctly
STATD$counter=$(eval "smartctl -H -l error \$DISK$counter" | grep -v "5.41" | grep -v "Joe")
eval echo \$STATD$counter
done
Don't use eval ever, except maybe if there is no other way AND you really know what you are doing.
The STATD$counter=$(...) should give an error. That's not a valid assignment because the string "STATD$counter" is not a valid variable name. What will happen is (using a concrete example, if counter happened to be 3 and your pipeline in the $( ) output "output", bash will only expand that line as far as "STATD3=output" so it will try to find a command named "STATD3=output" and run it. Odds are this is not what you intended.
It sounds like everything you want to do can be accomplished with arrays instead. If you are not familiar with bash arrays take a look at Greg's Wiki, in particular this page or the bash man page to find out how to use them.
For example, in the loop you didn't post in your question: make disk (not DISK: don't use all upper case variable names) an array like so
disk+=( "new value" )
or even
disk[counter]="new value"
Then in the loop in your question, you can make statd an array as well and assign it with values from disk by
statd[counter]="... ${disk[counter]} ..."
It's worth saying again: avoid using eval.

Shell script input containing asterisk

How do I write a shell script (bash on HPUX) that receives a string as an argument containing an asterisk?
e.g. myscript my_db_name "SELECT * FROM table;"
The asterisk gets expanded to all the file names in the current directory, also if I assign a variable like this.
DB_QUERY="$2"
echo $DB_QUERY
The asterisk "*" is not the only character you have to watch out for, there's lots of other shell meta-charaters that can cause problems, like < > $ | ; &
The simple answer is always to put your arguments in quotes (that's the double-quote, " ) when you don't know what they might contain.
For your example, you should write:
DB_QUERY="$2"
echo "$DB_QUERY"
It starts getting awkward when you want your argument to be used as multiple parameters or you start using eval, but you can ask about that separately.
You always need to put double quotes around a variable reference if you want to prevent it from triggering filename expansion. So, in your example, use:
DB_QUERY="$2"
echo "$DB_QUERY"
In the first example, use single quotes:
myscript my_db_name 'SELECT * FROM table;'
In the second example, use double quotes:
echo "$DB_QUERY"

Resources