回显环境变量 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! 的建议),而将命令 打印另一个命令 在变量只是在自找麻烦。
我有两个 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! 的建议),而将命令 打印另一个命令 在变量只是在自找麻烦。