Getting variable values from variable names listed in array in Bash - bash

I'm trying to print values of multiple variables that are listed in a Bash array as evident in the minimal code example below.
#!/bin/bash
VAR1="/path/to/source/root"
VAR2="/path/to/target/root"
VAR3="50"
VARS=("VAR1" "VAR2" "VAR3")
for var in ${VARS[*]}; do
echo "value of $var is ${$var}"
done
This gives me an error
line 8: value of $var is ${$var}: bad substitution
I want the following output:
value of VAR1 is /path/to/source/root
value of VAR2 is /path/to/target/root
value of VAR3 is 50
My search on Google and SO was not very fruitful. Because of the indirection (i.e., var iterates over an array containing names of variables for which I want the values), I'm not able to precisely word my search. But any help is appreciated.

Use indirect reference as:
#!/bin/bash
VAR1="/path/to/source/root"
VAR2="/path/to/target/root"
VAR3="50"
VARS=("VAR1" "VAR2" "VAR3")
for var in ${VARS[*]}; do
echo "value of $var is ${!var}"
done
Output:
value of VAR1 is /path/to/source/root
value of VAR2 is /path/to/target/root
value of VAR3 is 50

Related

Bash - Assigning existing Variable values to a New Variable. New Variable values does not return the assigned value

I want to assign a value of the existing Variable to a new Variable in my Bash script.
The issues is that once the New variable gets assigned to a value of the existing Variable it returns none instead of returning the existing variable value. (see code below):
VAR1="Hello World"
VAR2="Let's concatenate"
VAR1+="$MyVar" # assigning to a new variable
echo "$VAR1"
echo "$MyVar" # This is the issue --> no value returned (intention is to return "Hello World")
The output is for this command (echo "$MyVar") is:
VAR1=
echo ''
You aren't defining a new variable named MyVar. You are appending the empty string resulting from the expansion of the non-existent variable to the value of VAR1.
You want
MyVar=$VAR1
to get the desired result.
An example of what += does do:
$ x=foo
$ echo "$x"
foo
$ x+=bar
$ echo "$x"
foobar

How to crete a TSV file using Bash that takes as input some shell variables?

I have some shell variables which equal different types of values :
variable 1: 72.9%
variable 2: 27.1%
variable 3: Y
variable 4: 8756
I want to be able to print the values of these variables to a tab separated file and possibly even have the name of the variables as column headers
output:
variable1 variable2 variable3 variable4
72.9% 27.1% Y 8756
Any ideas?
Relatively easy, you just need to read the values one line-at-a-time into individual array variables and then provide the formatted output, e.g.
#!/bin/bash
declare -a name
declare -a num
declare -a value
while read -r a b c; do
name+=( "$a" )
num+=( "$b" )
value+=( "$c" )
done < "$1"
## C-style loop used to index both name & num for headings
for ((i = 0; i < ${#name[#]}; i++)); do
printf "%s\t" "${name[i]}${num[i]%:}"
done
echo
for i in "${value[#]}"; do
printf "%s\t\t" "$i"
done
echo
Which will result in tab separated headings and values (you may need to play with the spacing a bit -- e.g. using 2 tabs on value output)
Example Use/Output
$ bash headings.sh csvdata.txt
variable1 variable2 variable3 variable4
72.9% 27.1% Y 8756
If you have the variables in the script itself, you will have to take the same approach. With a variable, you have the name, but will need to create an array holding the names, as well as the values in order to loop over the values to provide the output you want. Whether you write a temp_file and read the values in, or use arrays to store the names of the variables (created by string concatenation between the number num above) the process will be the same.
Variables Already In Script
As mentioned above, you will take a similar approach, only here, you choose the heading prefix, and just use the loop counter to add the number at the end of whatever name you choose, then simply loop over the values you have stored in the array, e.g.
#!/bin/bash
foo="72.9%"
bar="27.1%"
baz="Y"
buz="8756"
declare -a value
value=( "$foo" "$bar" "$baz" "$buz" )
for ((i = 0; i < ${#value[#]}; i++)); do
printf "%s\t" "variable$((i+1))"
done
echo
for i in "${value[#]}"; do
printf "%s\t\t" "$i"
done
echo
Example Use/Output
(the same)
$ bash headings2.sh
variable1 variable2 variable3 variable4
72.9% 27.1% Y 8756

Unable to execute printf command by using formatter and argument variable

I am trying to store all the printf formatter and arguments into their own respective variables to be execute later. Example code:
var="abc123"
var2="def 456"
printfArgument=$var" "$var2
formatter="%-10s"
formatter2="%-10s"
printfFormatter=$formatter" "$formatter2"\n"
printf "$printfFormatter" $printfArgument
output:
abc123 def
456
It seems like the space in var2 causes the 456 to display improperly. Any way to fix it?
You're correct; the space in var2 is being used for word-splitting. printf is receiving 3 arguments after the format string: abc123, def, and 456. The first two fill the two format specifiers for the first line of output. Since there is a remaining argument, the format string is used again to produce the second line of output.
You need to use an array for printfArgument:
printfArgument=( "$var" "$var2" )
printf "$printfFormatter" "${printfArgument[#]}"
or just use var and var2 separately:
printf "$printfFormatter" "$var" "$var2"

How can I read out the values of dynamically declared bash variables?

I have some trouble with a bash script, maybe someone can help me.
Inside my script, I defined variables dynamically using a loop like this:
somecolors="red yellow green blue" # read out of a file, may vary
for color in $(echo $somecolors); do
# Actually, here is more code that generates the value I
# want to set for this variable, that is being written
# into "$value"
declare use_color_$color=$value
done
The result is that four variables have been defined:
use_color_red=1
use_color_yellow=1
use_color_green=1
use_color_blue=1
So far so good. But how can I dynamically read these? I thought of suing a "for" loop. For example:
for color in $(echo $colors); do
echo $use_color_${color}
done
But this does not work.
How can I compose two variable names to a single one?
Thanks in advance!
Better use indexed and associative arrays instead. Referencing and dereferencing variable variables that way is really wrong.
somecolors=(red yellow green blue)
declare -A use_color
for color in "${colors[#]}"; do
use_color[$color]=$value ## Or do you mean use_color[$color]=$color?
done
Granting $value == 1, when you do echo "${use_color[red]}" you'd get 1.
One variation:
declare colors=(red yellow green blue)
declare -A use_color
use_color[red]=1
use_color[yellow]=1
use_color[green]=1
use_color[blue]=1
for color in "${colors[#]}"; do
echo "use_color[$color]=${use_color[$color]}"
done
Output:
use_color[red]=1
use_color[yellow]=1
use_color[green]=1
use_color[blue]=1
Similarly:
declare -A use_color=([red]=1 [yellow]=1 [green]=1 [blue]=1)
for color in "${!use_color[#]}"; do
echo "use_color[$color]=${use_color[$color]}"
done
Output:
use_color[yellow]=1
use_color[red]=1
use_color[blue]=1
use_color[green]=1
The cleanest way is using variable substitution. A variable of the form ${!varabc} will match all previously defined variables beginning with varabc. In your case:
#!/bin/bash
use_color_red=1
use_color_yellow=1
use_color_green=1
use_color_blue=1
for i in ${!use_color#}; do
printf " name: %-16s value: %d\n" $i ${!i}
done
exit 0
output:
name: use_color_blue value: 1
name: use_color_green value: 1
name: use_color_red value: 1
name: use_color_yellow value: 1

Bash scripting: find variable with lowest value

I have script containin 4 variables. Need a function that will take values of those 4 variables and return name of the one that has lowest value.
So let's say that i have:
var1=55
var2=71
var3=30
var4=42
then i would like it to return as an answer: var3
Can anyone help? I need easiest way to solve that but appreciate any working solution.
From your question I don't think your values are in an array and that you want to know which index in the array is smallest - I think your values are in individual variables and you want to know the name of the variable containing the smallest value. If that is really what you are asking try this:
func()
{
minvar=$1
eval minval=\$$1
for i in $*
do
eval var=\$$i
# echo $i=$var
if [[ $var -lt $minval ]]
then
minvar=$i
minval=$var
# echo min=$i
fi
done
}
var1=55
var2=71
var3=30
var4=42
func var1 var2 var3 var4
echo $minvar=$minval

Resources