How do I perform variable expansion of a string variable in bash?

I'm writing a simple tool bash debugging log_next_line

. Intended behavior: when a variable is defined log

, it reads the next script line, expands the variables on it, writes it to the file specified $log

, executes the command, and dumps its output to the same log.

I have a problem with variable expansion. Suppose I have a line of bash code in a variable $line

. How can I expand the lines in it without executing any external programs and without executing protocols (which is dangerous)?

Simple line=$("echo $line")

doesn't work at all. When I try line=$(bash -c "echo $line")

, I'm in luck, but then I need to export ALL bash variables to a spawned bash (which I have no idea how to do). And calling an external program seems overkill for her; in addition, bash will execute pipes and external programs if for example line="echo $(rm -r /)"

.

Is there a way to do variable expansion that doesn't involve writing a bash parser from scratch ;-)? I need it to work under Linux (Ubuntu> = 14.04 to be precise).

For the complete picture, I include the function prototype:

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" >>$log #Writes the variable-expanded line to the log
        $line >>$log 2>>$log #Executes the line and 
        exitstatus=$?
        if [ "$exitstatus" -ne "0" ]; then
            echo "## Exit status: $exitstatus" >>$log
        fi
        echo >>$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
}

      

And a simple script that can be used as a test case

#!/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 > /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

      


unit tests:

if x=a

, a="example"

then I want the following extensions:

  • echo $x

    should be echo a

    .
  • echo ${!b}

    it should be echo example

  • touch ${!b}.txt>/dev/null

    it should be touch example.txt>/dev/null

  • if [ (( ${#a} - 6 )) -gt 10 ]; then echo "Too long string";fi

    it should be if [ 1 -gt 10 ]; then echo "Too long string";fi

  • echo "\$a and \$x"|tee file.txt

    it should be echo "\$a and \$x"|tee file.txt"


This question is a generalization of https://unix.stackexchange.com/questions/131150/bash-is-it-safe-to-eval-bash-command . The answers given here don't pass all of my test cases.

+3


source to share


1 answer


the function can be implemented as simple set -x

to enable tracing at a given point in the script and set +x

to disable it.



If you definitely want to implement it as a single line flag, I would go over this question and set up the flag -x

through the DEBUG hook.

+1


source







All Articles