如何在bash中执行字符串变量的变量扩展?

时间:2014-11-27 19:42:13

标签: bash shell parsing debugging environment-variables

我正在编写一个简单的bash调试工具log_next_line。预期的行为是在定义log变量时,它读取脚本的下一行,在其上展开变量,将其写入$log指定的文件,执行命令,并将其输出捕获到相同的日志。

我有变量扩展的问题。假设我在变量$line中有一行bash代码。如何在不执行任何外部程序的情况下扩展其中的字符串,并且不执行管道(这是危险的)?

简单的line=$("echo $line")根本不起作用。 当我尝试line=$(bash -c "echo $line")我有更好的运气,但后来我需要将所有bash变量导出到生成的bash(我不知道该怎么做)。为它调用外部程序似乎是一种过度杀伤力;除了bash将执行管道和外部程序,如果line="echo $(rm -r /)"

有没有办法进行变量扩展,不涉及从头开始编写Bash解析器;-)?我只需要它在Linux下运行(准确地说Ubuntu> = 14.04)。

为了获得完整的图片,我包含了函数的原型:

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
}

可以用作测试用例的简单脚本

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

单元测试:

如果x=aa="example",那么我希望进行以下扩展:

  1. echo $x应为echo a
  2. echo ${!b}应为echo example
  3. touch ${!b}.txt>/dev/null应为touch example.txt>/dev/null
  4. if [ (( ${#a} - 6 )) -gt 10 ]; then echo "Too long string";fi应为if [ 1 -gt 10 ]; then echo "Too long string";fi
  5. echo "\$a and \$x"|tee file.txt应为echo "\$a and \$x"|tee file.txt"

  6. 这个问题是https://unix.stackexchange.com/questions/131150/bash-is-it-safe-to-eval-bash-command的概括。那里给出的答案并没有通过我的所有测试用例。

1 个答案:

答案 0 :(得分:1)

该函数可以实现为简单的set -x,以便在脚本的给定点启用跟踪,并set +x将其关闭。

如果你肯定希望将它作为单行标志实现,我会看一下this question并通过DEBUG陷阱配置-x标志。