how to use variable variable names in bash script [duplicate] - bash

This question already has answers here:
How to use a variable's value as another variable's name in bash [duplicate]
(6 answers)
Closed 6 years ago.
I'm trying to get the values of some php variables into a bash script in order to set other bash variables. Basically I need to be able to access the value of a variable - variable name.
the script can find & read the file, find the php variables, but when I try to set them it just hangs. Here is what I have:
variables=(database_user database_password dbase);
paths=(modx_core_path modx_connectors_path modx_manager_path modx_base_path);
for index in "${variables[#]}"; do
index=\$$index
echo $index;
$index="$(grep -oE '\$${!index} = .*;' $config | tail -1 | sed 's/$${!index} = //g;s/;//g')";
done
not sure what I am doing wrong here...

You are trying to perform an indirect assignment.
You should get rid of these two lines :
index=\$$index
echo $index;
By simply writing :
echo "${!index}"
Which does an indirect expansion cleanly (gives you the value of the variable whose name is contained in variable index).
Next, the problematic line is this one:
$index="$(grep -oE '\$${!index} = .*;' ... (rest omitted)
In Bash, an assignment cannot begin with a $.
One way you can perform an indirect assignment is this (after removing the index re-assignment as suggested above) :
printf -v "$index" "$(grep -oE '\$${!index} = .*;' ... (rest omitted)
This uses the -v option of printf, which causes the value passed as the final argument to be assigned to a variable, the name of which is passed to the -v option.
There are other ways of handling indirect assignment/expansions, some with code injection risks, as they use (potentially uncontrolled) data as code. This is something you may want to research further.
Please note I am assuming the actual grep command substitution works (I have not tested).

Related

How to make a string, not a value of a variable but a new variable? [duplicate]

This question already has answers here:
Dynamic variable names in Bash
(19 answers)
Closed last year.
I have these variables:
var1=ab
var2=cd
result=${var1}-text-${var2}
ab-text-cd=bingo
I have:
$ echo $result
ab-text-cd
I would like to have:
$ echo $result
bingo
Is it possible and how?
More info:
Var1 and var2 are arguments given to script.
Thanks to #Léa Gris.
I didn't know about "indirect parameter expansion".
"If the first character of PARAMETER is an exclamation point, Bash uses the value of the variable formed from the rest of PARAMETER as the name of the variable."
Solution :
result2=$(echo ${!result1})
You can use eval to achieve this. Be warned though, that using eval is almost always a bad idea, as it has glaring security issues (rooted in its design -- it is meant to execute everything passed to it) and even apart from that, all kinds of things might go wrong when a variable has an unexpected value.
result=${var1}-text-${var2}
eval ${var1}'_text_'${var2}=bingo
echo $ab_text_cd
Also, environment variables cannot have dashes (-) as part of the variable name, so I replaced them by underscores (_) for the example.

Bash - Add variable in associative array - bad substitution [duplicate]

This question already has answers here:
Bash indirect variable referencing
(1 answer)
Bash indirect array addressing?
(3 answers)
Closed 2 years ago.
Here is an expected behavior for associated array in bash
$ declare -A PC=( [Monitor]=Dell [CPU]=HP )
$ echo ${PC[CPU]}
HP
This gives me HP as output
Lets say I have these PC,Monitor amd CPU values stored in variable a , b and c. I am trying fetch the details now but I am getting "bad substitution" error when trying so.
$ a=PC; b=Dell; c=HP
$ echo ${$a[$b]}
bash: ${$a[$b]}: bad substitution
$ echo ${PC[$b]}
Dell
${PC[$b]} however is returning expected output but not {$a[$b]}
Not sure how this can be achieved. Thanks in advance.
What you are trying to do is called indirection - using one variable as the name of another variable.
In bash you do this for normal variables using the syntax ${!var}, as in
a=5
b=a
echo ${!b} # 5
Unfortunately this won't work how you want for an array variable because the syntax ${!array[*]} means something else (getting all keys from an associative array).
Instead, as suggested by a comment below, you can create a string for the entire reference and then use redirection on that:
lookup="$a[$b]"
echo ${!lookup} # will give Dell in your example

create multiple global variables from a loop in bash [duplicate]

This question already has answers here:
Indirect variable assignment in bash
(7 answers)
Dynamic variable names in Bash
(19 answers)
Closed 4 years ago.
So I have a loop that basically goes through all of the disks installed on the system, then it assigns a variable to a disk name. however, I cannot use those variables if it's not inside the loop, how do I make them available to be used in other functions or other parts of the script?
Here is the code
#!/bin/bash
dev=1
for disk in $(fdisk -l | grep -o '/dev/sd[a-z]'); do
set "DISK$dev=$disk"
dev=$((dev+1))
done
So if I do echo $DISK1 for example, it doesn't display anything.
But if I do echo $DISK1 INSIDE the loop, then ir displays the fist variable assignment. Can I export them and make them available outside of the loop?
set is not at all the right command to use here. You could pull this off with eval where you have set; but the proper way to solve this is simply to assign the values to an array.
disks=($(fdisk -l | grep -o '/dev/sd[a-z]'))
You can loop over the individual entries with ${disk[0]} through ${disk[n]} or retrieve the entire array at once with "${disk[#]}". The expression ${#disk[#]} evaluates to the number of elements in the array; though because array indexing is zero-based, the last index is one less than this value.
Of course, very often, you don't really need to keep the results in a variable explicitly. If you don't need random access (do you need to recall what you know about the first disk when processing the fifth? Really?) you should probably just loop over the values directly.
for disk in $(fdisk -l | grep -o '/dev/sd[a-z]'); do
: whatever you need to do with the current "$disk"
done
You cannot directly access the parent scope. Also with "export" you will be able to access the exported variable to sub-shell but not the parent one.
A work around for this can be put all these set into a file (appending the new sets) and execute it with after the loop:
dev=1
for disk in $(fdisk -l | grep -o '/dev/sd[a-z]'); do
echo "export \"DISK$dev=$disk\";" >> my_script_full_of_sets.sh
dev=$((dev+1))
done
. my_script_full_of_sets.sh

Unable to print value of shell variable stored in another variable [duplicate]

This question already has answers here:
Lookup variable value from string in shell script
(2 answers)
Closed 8 years ago.
I'm trying to find all variables which match a particular pattern and print their values.
test_a="apple"
test_b="banana"
test_c="carrot"
test_d="doughnut"
test_show_all () {
local i
for i in ${!test_*}; do
printf "..$i\n"
# printf "..$i-->${$i}\n"
done
}
The loop is finding the correct variables.
But if I uncomment the second line of the for loop, bash is unhappy with the syntax ${$i}. I thought this should work since $i holds the name of a variable, so I thought ${$i} should expand to value of that stored name.
The indirect variable reference is ${!var}. Change your code to
printf "..$i-->${!i}\n"
and it should work.
Not useful now, but in bash 4.3, you will also be able to use namerefs.
for name in ${!test_*}; do
declare -n value=$name
printf "..$name->$value\n"
done
As a short cut, if you only want to iterate over the values (without regard to the actual name of the variable), you can use
declare -n value
for value in ${!test_*}; do
printf "..$value\n"
done

How to define dynamic variable in bash? [duplicate]

This question already has answers here:
How to create a bash variable like $RANDOM
(3 answers)
Closed 5 years ago.
I would like to have a shell variable that could be dynamically run every time it is refered, for example, i would like to have a variable $countPwd which could return the count of files/dirs in the current directory, it could be defined as:
countPwd=`ls | wc -l`
and if I do echo $countPwd it would only show the value when I define the variable, but it won't update automatically when I change my current directory. So how do I define such a variable in bash that the value of it get updated/calculated on the fly?
Update:
The $PWD is a perfect example of a variable get evaluated in the real time. You don't need to use $() or backticks `` to evaluate it. How is it defined in bash?
Make a function:
countPwd() {
ls | wc -l
}
Then call the function like any other command:
echo "There are $(countPwd) files in the current directory."
Another option: store the command in a variable, and evaluate it when required:
countPwd='ls | wc -l'
echo $(eval "$countPwd")
You'll need to write some C code: write a bash's loadable buitins to do the heavy lifting in defining variables with dynamic values like $SECONDS or $RANDOM ($PWD is just set by cd).
More details in my answer here (a duplicate of this question).

Resources