回显环境变量 returns 字符串文字而不是环境变量值

Echo-ing an environment variable returns string literal rather than environment variable value

我有两个 bash 脚本。第一个侦听管道 "myfifo" 的输入并将输入作为命令执行:

fifo_name="myfifo"

[ -p $fifo_name ] || mkfifo $fifo_name;

while true
do
  if read line; then
    $line
  fi
done <"$fifo_name"

第二个将命令 'echo $SET_VAR' 传递给 "myfifo" 管道:

command='echo $SET_VAR'
command_to_pass="echo $command"
$command_to_pass > myfifo

如您所见,我想通过管道传递 'echo $SET_VAR'。在侦听器进程中,我设置了一个 $SET_VAR 环境变量。我希望命令 'echo $SET_VAR' 的输出为 'var_value,',这是环境变量 SET_VAR.

的值

运行 一个 bash 进程中的第一个(侦听器)脚本,然后通过另一个进程中的第二个脚本传递命令,结果如下:

$SET_VAR

我希望 "var_value" 能够打印出来。相反,字符串文字 $SET_VAR 被打印出来。为什么会这样?

bash,本质上是从 stdin 读取命令。你可以简单地 运行:

bash < myfifo

在解决您报告的问题之前,我必须指出您的循环无法正常工作。 while true 部分(在循环中某处没有 break )将永远 运行 。它将从文件中读取第一行,循环,尝试读取第二行(失败),再次循环,尝试读取第三行(也失败),再次循环,尝试读取第四行,等等。 .. 您希望循环在 read 命令失败后立即退出,因此请使用:

while read line
do
    # something I'll get to
done <"$fifo_name"

您遇到的另一个问题是 shell 扩展变量(即将 $var 替换为变量 var 的值)中途 解析命令行的过程,完成后不会返回并重新执行前面的解析步骤。特别是,如果变量的值包含 $SET_VAR 之类的内容,它不会返回并扩展它,因为它刚刚完成扩展变量的位。事实上,它对扩展值所做的唯一事情就是将它拆分为 "words"(基于空格),并扩展它找到的任何文件名通配符——没有发生变量扩展,没有引号或转义解释等。

一个可能的解决方案是用eval命令告诉shell到运行解析过程两次

while read line
do
    eval "$line"
done <"$fifo_name"

(请注意,我在 "$line" 周围使用了双引号——这可以防止我提到的单词拆分和通配符扩展发生 before eval通过正常的解析过程。如果你认为你的原始代码半解析了 $line 中的命令,没有双引号,它得到 一个半解析 ,这是很奇怪。双引号抑制了半解析阶段,所以变量的内容只被解析一次。)

但是,这个解决方案带有一个很大的警告,因为 eval 作为错误磁铁享有当之无愧的声誉。 eval 使复杂的事情变得容易,而无需完全了解正在发生的事情,这意味着您往往会获得在测试中运行良好的脚本,然后在以后无法理解地失败。根据我的经验,当 eval 看起来是最佳解决方案时,这可能意味着您正在尝试解决错误的问题。

那么,你到底想做什么?如果您只是试图将来自 fifo 的行作为 shell 命令执行,那么您可以在子 shell 中使用 bash "$fifo_name" 到 运行 它们,或者 source "$fifo_name" 到 运行 他们在当前 shell.

顺便说一句,提供 fifo 的脚本:

command='echo $SET_VAR'
command_to_pass="echo $command"
$command_to_pass > myfifo

也是一场灾难等待发生。将命令放在变量中在 shell 中效果不佳(我支持 chepner 对 BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail! 的建议),而将命令 打印另一个命令 在变量只是在自找麻烦。