我有两个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。为什么会这样?
答案 0 :(得分:3)
在我遇到你报告的问题之前,我必须指出你的循环不起作用。 while true
部分(循环中没有break
)将永远运行。它将从文件读取第一行,循环,尝试读取第二行(失败),再次循环,尝试读取第三行(也失败),再次循环,尝试读取第四行等。 ..一旦read
命令失败,您希望循环退出,因此请使用:
while read line
do
# something I'll get to
done <"$fifo_name"
你遇到的另一个问题是shell扩展了变量(即将$var
替换为变量var
的值)中途解析a的过程命令行,当它完成时它不会返回并重新执行早期的解析步骤。特别是,如果变量的值包含$SET_VAR
之类的内容,则它不会返回并扩展它,因为它刚刚完成扩展变量的位。实际上,它对扩展值的唯一作用是将其拆分为“单词”(基于空格),并展开它找到的任何文件名通配符 - 不会发生变量扩展,没有引用或转义解释等。
一种可能的解决方案是使用eval
命令告诉shell运行解析过程两次:
while read line
do
eval "$line"
done <"$fifo_name"
(请注意,我在"$line"
周围使用了双引号 - 这可以防止我提到的单词拆分和通配符扩展在 eval
经过正常解析过程之前发生如果你认为你的原始代码在$line
中半解析命令,没有双引号就会得到一个半解析的,这很奇怪。双引号抑制了一半-parsing stage,因此变量的内容只需解析一次。)
然而,这个解决方案带有一个很大的警告,因为eval
作为一个臭虫磁铁享有当之无愧的声誉。 eval
可以很容易地完成复杂的事情而不必了解正在发生的事情,这意味着您倾向于获得在测试中运行良好的脚本,然后在以后无法理解。根据我的经验,当eval
看起来是最好的解决方案时,它可能意味着你正试图解决错误的问题。
那么,你究竟想做什么?如果您只是尝试执行来自fifo的行作为shell命令,那么您可以使用bash "$fifo_name"
在子shell中运行它们,或source "$fifo_name"
在当前shell中运行它们。
BTW,提供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!),并且在变量中输入命令来打印另一个命令只是在乞求麻烦。
答案 1 :(得分:1)
bash
,本质上,从stdin
读取命令。你可以简单地运行:
bash < myfifo