Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'd like to somehow spit out a file (which has env variable references) and substitute the actual values. This is what I've tried, but as you can see it's not working. Any ideas?

-bash-3.00$ cat vars_file 
${MY_VAR}
-bash-3.00$ export MY_VAR=MY_VALUE; cat ./vars_file | xargs echo
${MY_VAR}
share|improve this question
add comment

4 Answers

up vote 5 down vote accepted

Old thread, but this is a recurrent issue. Here is a solution using bash's mapfile:

mateus@mateus:/tmp$ cat input.txt
a = $a
b = $b
mateus@mateus:/tmp$ echo a=$a, b=$b
a=1, b=2
mateus@mateus:/tmp$ function subst() { eval echo -E "$2"; }
mateus@mateus:/tmp$ mapfile -c 1 -C subst < input.txt
a = 1
b = 2

The bash builtin mapfile calls user-defined function subst (see -C/-c options) on each line read from input file input.txt. Since the line contains unescaped text, eval is used tu evaluate it and echo the transformed text to stdout (-E avoid special characters to be interpreted).

IMHO this is a much more elegant than any sed/awk/perl/regex based solution.

Another possible solution is to use shell's own substitution. This looks like a more "portable" way not relaying on mapfile:

mateus@mateus:/tmp$ eval echo "\"$(cat <<EOF_$RANDOM
$(<input.txt)
EOF_$RANDOM
)\""
a = 1
b = 2

Note we use EOF_$RANDOM to minimize conflicting cat's here-document with input.txt content.

Both examples from: https://gist.github.com/4288846

EDIT: Sorry, the first example do not treats comments and white space correctly. I'll work on that and post a solution.

share|improve this answer
add comment

As described in the same thread at http://www.issociate.de/board/post/281806/sed_replace_by_enviroment_var_content.html, the "proper" solution would be as follows:

awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < input.txt > output.txt

eval approach is fine, but tends to fail on XML files for instance.

share|improve this answer
add comment

Can be done with script (e.g. file name is expand.sh):

while read line; do eval echo \"$line\"; done < $1 > $2

The script may be called like this:

env VAR1=value1 sh expand.sh input_file output_file

http://www.issociate.de/board/post/281806/sed_replace_by_enviroment_var_content.html

share|improve this answer
    
any idea how to do this when there's a paren in the file? -bash: syntax error near unexpected token `(' –  andersonbd1 Jan 20 '11 at 17:51
    
@andersonbd1: I suppose you could replace the parentheses with sed and replace them back later. Otherwise, you might want to consider to remove the accept mark from my answer to get a better awk solution, as the above questions mentions that you can't read the effect with sed. –  Tom Wijsman Jan 20 '11 at 18:09
1  
I guess sed is my best bet. It ain't pretty but it'll work. Thanks TomWij –  andersonbd1 Jan 20 '11 at 18:24
    
You might want to quote that variable: echo "$line". @andersonbd1: what is the context of the parentheses? –  Dennis Williamson Jan 20 '11 at 19:06
1  
Oops, sorry, I forgot to say that you should use read -r, too. –  Dennis Williamson Jan 20 '11 at 19:14
show 1 more comment

Here's my proposed solution:

eval $'cat <<\002\n'"$(<ifile)"$'\n\002' > ofile

\002 can be replaced with any character or string that doesn't occur in the ifile. To delete any occurrences of the delimiting character in the input file:

eval $'cat <<\002\n'"$(tr -d '\002' < ifile)"$'\n\002' > ofile

This solution seems to resolve most issues but is notably vulnerable to command injection in the template file through $(command) directives.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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