title: How to perform a variable expansion of the string variable in bash?
body: <p>I am writing a simple bash debugging tool, <code>log_next_line</code>. The intended behavior is when the <code>log</code> variable is defined it reads next line of the script, expand variables on it, writes it to the file specified by <code>$log</code>, executes the command, and capture its output to the same log.</p>
  
  <p>I have the problem with the variable expansion. Suppose I have a line of bash code in variable <code>$line</code>. How to expand the strings in it without executing any external programs, and without executing pipes (which is dangerous)?</p>
  
  <p>The simple <code>line=$("echo $line")</code> doesn't work at all. 
  When I try <code>line=$(bash -c "echo $line")</code> I have better luck, but then I need to export ALL bash variables to the spawned bash (which I have no idea how to do). And calling the external program for it seems like a overkill; besides the bash will execute the pipes and external programs, if e.g. <code>line="echo $(rm -r /)"</code>. </p>
  
  <p>Is there any way to do the variable expansion that will not involve writing a Bash parser from scratch ;-) ? I only need it to work under Linux (Ubuntu >= 14.04 to be precise).</p>
  
  <p>For a full picture I include the prototype of the function:</p>
  
  <pre><code>function log_next_line()
  {
      if [ -n "$log" ]; then
          file=${BASH_SOURCE[1]##*/}  #Takes path to the file, from where the function is called
          linenr=$((${BASH_LINENO[0]} + 1 )) #Line number
          line=`sed "${linenr}q;d" $file` #Reads this line number from the source file
          line=$("echo $line") #DOESN'T WORK. I want it to do a variable expansion
          echo "\$ $line" &gt;&gt;$log #Writes the variable-expanded line to the log
          $line &gt;&gt;$log 2&gt;&gt;$log #Executes the line and 
          exitstatus=$?
          if [ "$exitstatus" -ne "0" ]; then
              echo "## Exit status: $exitstatus" &gt;&gt;$log
          fi
          echo &gt;&gt;$log
          BASH_LINENO[0]=$((BASH_LINENO[0] + 1)) #Skips executing of the next line, since we have already executed it (and captured its output)
          if [ "$exitstatus" -ne "0" ]; then
              exit $exitstatus
          fi
      fi
  }
  </code></pre>
  
  <p>And the simple script that can be used as a test case</p>
  
  <pre><code>#!/bin/bash
  
  log=mylog.log
  
  . ./log_next_line.sh
  
  rm mylog.log
  
  a=4
  b=example
  x=a
  
  log_next_line
  echo $x
  log_next_line
  echo ${!b}
  log_next_line
  touch ${!b}.txt &gt; /dev/null
  log_next_line
  touch ${!x}.txt
  log_next_line
  if [ (( ${#a} - 6  )) -gt 10 ]; then echo "Too long string";fi
  log_next_line
  echo "\$a and \$x"|tee file.txt
  </code></pre>
  
  <hr>
  
  <p>unit tests:</p>
  
  <p>if <code>x=a</code>, <code>a="example"</code> then I want the following expansions:</p>
  
  <ol>
  <li><code>echo $x</code> should be <code>echo a</code>. </li>
  <li><code>echo ${!b}</code> should be <code>echo example</code></li>
  <li><code>touch ${!b}.txt&gt;/dev/null</code> should be <code>touch example.txt&gt;/dev/null</code></li>
  <li><code>if [ (( ${#a} - 6  )) -gt 10 ]; then echo "Too long string";fi</code> should be <code>if [ 1 -gt 10 ]; then echo "Too long string";fi</code></li>
  <li><code>echo "\$a and \$x"|tee file.txt</code> should be <code>echo "\$a and \$x"|tee file.txt"</code></li>
  </ol>
  
  <hr>
  
  <p>This question is a generalization of the <a href="https://unix.stackexchange.com/questions/131150/bash-is-it-safe-to-eval-bash-command">https://unix.stackexchange.com/questions/131150/bash-is-it-safe-to-eval-bash-command</a> . The answers given there don't pass all my test cases. </p>