2

i have a text file variables.txt where i store my variables

host=/srv/www/vhosts/hosting

index=$host/index.php

as you see the second variables depends on the first one.

i also have a script file to load these variables

f=~/variables.txt
for line in $(cat $f)
do
export $line
done

when i execute the script file, my first variable gets loaded, while the second doesn't:

bash: $host/index.php: No such file or directory

it's because after loading the first variable host, it doesn't remember its value to use for setting the second variable index.

So how to solve this problem? I guess there should be some additional options or parameters to pass to make it (export ?) remember the set variable value in a for loop.

3

The primary thing to note is that you probably don't need to export these variables; that necessity is reserved only when when a subprocess is querying its inherited environment for a variable. Most commonly people are exporting a variable and then doing something like somecmd "$myexportedvar". Your shell is expanding $myexportedvar before somecmd ever sees it.

If you really do need to export these for a subprocess to pull from its environment:

while IFS= read -r line; do
  if [[ $line == *=* && $line != #* ]]; then
    IFS== read -r var val <<<"$line"
    printf -v "$var" '%s' "$val"
    export "$var"
  fi
done < "$HOME/variables.txt"

this loop checks that the line is an assignment (kinda) and that the first character is not a comment hash. makes the effort a little more robust, but just barely. see the two options below instead, for handling this more carefully.

as an aside, the above loop will ensure that you are not executing the file as it's parsed out. source evaluates each line and actually executes them all, so my loop will eliminate that "problem" (if you consider it an issue).

Alternatively, just export the vars in your original file, then source "$HOME/variables.txt" and the work is already done.

you may want to just use set -a; . "$HOME"/variables.txt; set +a. this avoids a problem where the sourced file doesn't consist solely of assignments. the parsing loop above can result in false-positives. read help set to understand what it's doing.

Also, Don't Read Lines With For and Use More Quotes

2

you have a easier way to perform that.

cat vars
host=/srv/www/vhosts/hosting
index=$host/index.php

my test script:

#!/bin/bash
. ./vars
echo $host
echo $index

Execution

./printvars.sh
/srv/www/vhosts/hosting
/srv/www/vhosts/hosting/index.php

Basically the . ./vars executes the files and loads the variables.

  • i know, but my actual file is too big and filled up with variable definitions, that i want to export with a for loop. i don't want to write export command on each line in my variables.txt file and then to source it, i want to do it with for loop instead. – easl Jul 23 '13 at 7:41
  • 2
    The command sed 's/^/export /' vars writes "export" at the beginning of each line in vars. This is unix, you're trying to do it the hard way. – msw Jul 23 '13 at 18:56
1

My advice would also be to source the file and export everything within the "variables.txt" file. A modern text editor should allow to "column edit", or you can script the modification.

However, I managed to answer your question with this script :

#!/bin/sh

f=./variables.txt
source ${f}
for vname in $(cut -f1 -d'=' ${f})
do
    export ${vname}
done

The difference is that I source the variables.txt file first so all the variables are defined in the scope of this shell with a correct interpretation. Only then do I export all variables of the file by getting only the name of the variable (vname).

On a side note, you should protect your variables with ${}.

  • as an aside to your aside, one should only use curly braces for two things: disambiguation between a variable's name and other coinjoined text "${var}string", and alternatively for Parameter Expansions "${name:-default}". "Protecting" variables is to be done with double-quotes. Use More Quotes – Josh McGee Jul 23 '13 at 19:12
0

You can do it in two steps:

. ./vars
while read line; do
    export $(printf "%s" "$line" | grep = | cut -d= -f 1)
done < vars

or just one

while read line; do
   eval export "$line"
done < vars

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.