【问题标题】:Echo-ing an environment variable returns string literal rather than environment variable value回显环境变量返回字符串文字而不是环境变量值
【发布时间】:2017-03-02 18:54:53
【问题描述】:

我有两个 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 environment-variables echo fifo


【解决方案1】:

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

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

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

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

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

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

但是,这个解决方案带有一个很大的警告,因为eval 拥有当之无愧的吸虫器声誉。 eval 让您在不完全了解发生了什么的情况下轻松完成复杂的事情,这意味着您往往会得到在测试中运行良好的脚本,然后在以后无法理解地失败。根据我的经验,当eval 看起来是最好的解决方案时,这可能意味着您正在尝试解决错误的问题。

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

顺便说一句,提供先进先出的脚本:

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! 的建议),并且将命令 打印另一个命令 放入变量中只是自找麻烦。 p>

【讨论】:

  • eval 似乎没有按照您的建议执行。 $SET_VAR 在 eval 执行后仍然是一个文字(在我的机器上)。
  • @nickackerman42 这很奇怪;这个对我有用。尝试将set -x 放在while read 循环之前,它会在执行命令之前打印命令(带有“+”前缀)。在我的测试中,它打印“+ read line”、“+ eval 'echo $SET_VAR'”、“++ echo This is the set_var value”、“This is the set_var value”(echo 输出),最后"+ read line"(失败,退出循环和脚本)。
【解决方案2】:

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

bash < myfifo

【讨论】:

    猜你喜欢
    • 2020-09-04
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 2018-09-30
    • 1970-01-01
    • 2014-08-16
    • 2013-06-11
    • 1970-01-01
    相关资源
    最近更新 更多