ofbahar
ofbahar

Reputation: 43

Reading variable name from txt file

I want to read variable name from txt file in bash script.

For example

I run var="thanks" in terminal
I create file.txt and txt file contains $var
I create variable var2 in terminal. var2=""
Then I run var2=$(<file.txt) command in terminal.

The Problem is

$ echo $var2
"$var"

I want the output of the echo $var command to be "thanks"

$ echo $var2
"thanks"

So what should I do?

Upvotes: 3

Views: 1173

Answers (2)

F. Hauri  - Give Up GitHub
F. Hauri - Give Up GitHub

Reputation: 70722

Two different bash way for this:

1. Using ${!var} indirect expansion:

Anoter way for dropping $" if present:

IFS='$"' read -a var2 <file.txt
var2=(${var2[*]})
echo ${!var2}

Tests:

var=Hello\ world\!
echo '"$var"' >file.txt
cat file.txt 
"$var"

IFS='$"' read -a var2 <file.txt
var2=(${var2[*]})
echo ${!var2}
Hello world!

echo 'var' >file.txt 
cat file.txt 
var

IFS='$"' read -a var2 <file.txt
var2=(${var2[*]})
echo ${!var2}
Hello world!

Explanation:

  • IFS Input Field Separator (usually contain: $' \t\n' <space><tab><newline>). All characters in this field are treated as field separator, so don't appear in array.

  • IFS='..' read .. when variable definition prepend command, variable are only affected for this execution

  • -a var2 read make var2 an array. Use declare -p to show his content:

     IFS='$"' read -a var2 <file.txt
     declare -p var2
     declare -a var2=([0]="" [1]="" [2]="var")
    
  • ${var2[*]} will merge var's fields in a single string, separated by 1st $IFS character.

     echo "<${var2[*]}>"
     <  var>
    
  • var2=( foo bar baz ) will redefine var2 ignoring spaces (as any characters in $IFS)

     var2=(${var2[*]})  # This step become useless, in 2nd case, but harmless.
     declare -p var2
     declare -a var2=([0]="var")
    
  • ${!var2} is known as indirect expansion

     echo ${!var2}
     Hello world!
    

2. Using reference name: nameref

  • declare -n name=value make NAME a reference to the variable named by its value

IFS='$"' read -a var2 < file.txt
var2=(${var2[*]})
declare -p var2
declare -a var2=([0]="var")

declare -n var3=$var2
echo $var3
Hello world!

This is usefull as local -n in a function:

readFrom() {
    local var2
    IFS='$"' read -a var2 < $1
    var2=(${var2[*]})
    local -n target=$var2
    echo $target
}

Then

echo '"$var"' >file.txt
var=Hello\ world\!
readFrom file.txt 
Hello world!

Alternative to avoid forks when populating variables:

readFrom() {
    local var2
    IFS='$"' read -a var2 < $1
    var2=(${var2[*]})
    local -n target=$var2 result=${2:-INPUT}
    result=("$target")
}

Then

readFrom file.txt newvar
echo "$newvar"
Hello world!

Advantage of this:

  • you could populate any kind of variables like array of associative arrays
  • you could populate many variables in same function

Upvotes: 1

choroba
choroba

Reputation: 241758

If you put just var into the file without the $ and quotes, you can use variable indirection.

var2=$(< file.txt)
var2=${!var2}
echo $var2

Or, if you need the dollar sign and quotes, remove them using parameter expansion before applying the indirection

var2=$(< file.txt)
var2=${var2#'"$'}
var2=${var2%\"}
var2=${!var2}
echo $var2

Upvotes: 3

Related Questions