为什么 eval "$BASH_COMMAND" 会崩溃 bash?
Why does eval "$BASH_COMMAND" crash bash?
如果你在终端里运行 eval "$BASH_COMMAND"
,它会崩溃,终端window会消失。我无法理解为什么这个特定命令会崩溃 bash
。
奇怪的是,当我运行echo "$BASH_COMMAND"
时,出现了这样的情况:
$ echo "$BASH_COMMAND"
echo "$BASH_COMMAND"
另一件事是$BASH_COMMAND
没有值:
"$BASH_COMMAND"
bash: "$BASH_COMMAND": command not found
$BASH_COMMAND
确实有一个值:当前正在执行的命令。这在 trap
处理程序等情况下很有用,因此处理程序可以找出陷阱触发时正在执行的命令。但是,当您将 $BASH_COMMAND
作为常规命令的一部分使用时,事情会变得奇怪、循环和混乱。让我们看看你给出的例子:
echo "$BASH_COMMAND"
在此示例中,BASH_COMMAND
变量的值恰好是字符串 echo "$BASH_COMMAND"
,因此当 shell 解析命令行时,它扩展了变量引用,相当于:
echo 'echo "$BASH_COMMAND"'
注意:那里的单引号并不是命令的真正部分,它们只是我添加的内容,表示命令的那部分不应该进行变量扩展、双引号删除等。在真正的命令,这些不应该完成,因为 它们已经 完成了。无论如何,结果是按字面打印字符串,给出你看到的结果。
"$BASH_COMMAND"
同样,BASH_COMMAND
的值恰好是字符串 "$BASH_COMMAND"
,因此展开后它等同于:
'"$BASH_COMMAND"'
...并且没有该名称的命令,因此您会得到一个错误。
(实际上,unix 文件名中允许使用引号和美元符号,因此您可以命名一个脚本并将其放在 PATH
中的某个位置,然后 将 是一个有效的命令名称。我不特别推荐这样做。)
eval "$BASH_COMMAND"
这个比较复杂。 BASH_COMMAND
的值是字符串eval "$BASH_COMMAND"
,所以展开后相当于:
eval 'eval "$BASH_COMMAND"'
但是 eval
命令所做的是将其参数 运行 作为 shell 命令,包括所有通常的解析。所以,它 运行 是命令:
eval "$BASH_COMMAND"
...再次扩展 $BASH_COMMAND
,导致:
eval 'eval "$BASH_COMMAND"'
...这使得 eval
命令解析并且 运行:
eval "$BASH_COMMAND"
...这个循环永远持续下去。或者更确切地说,它最终 运行 耗尽了一些资源(可能是堆栈 space),因为它试图跟踪这个不断扩展的东西。显然这会导致处理不当的崩溃。
但无论细节如何,该命令都不可能起作用。它要求 shell 执行无限系列任务,并且无法成功结束。
如果你在终端里运行 eval "$BASH_COMMAND"
,它会崩溃,终端window会消失。我无法理解为什么这个特定命令会崩溃 bash
。
奇怪的是,当我运行echo "$BASH_COMMAND"
时,出现了这样的情况:
$ echo "$BASH_COMMAND"
echo "$BASH_COMMAND"
另一件事是$BASH_COMMAND
没有值:
"$BASH_COMMAND"
bash: "$BASH_COMMAND": command not found
$BASH_COMMAND
确实有一个值:当前正在执行的命令。这在 trap
处理程序等情况下很有用,因此处理程序可以找出陷阱触发时正在执行的命令。但是,当您将 $BASH_COMMAND
作为常规命令的一部分使用时,事情会变得奇怪、循环和混乱。让我们看看你给出的例子:
echo "$BASH_COMMAND"
在此示例中,
BASH_COMMAND
变量的值恰好是字符串echo "$BASH_COMMAND"
,因此当 shell 解析命令行时,它扩展了变量引用,相当于:echo 'echo "$BASH_COMMAND"'
注意:那里的单引号并不是命令的真正部分,它们只是我添加的内容,表示命令的那部分不应该进行变量扩展、双引号删除等。在真正的命令,这些不应该完成,因为 它们已经 完成了。无论如何,结果是按字面打印字符串,给出你看到的结果。
"$BASH_COMMAND"
同样,
BASH_COMMAND
的值恰好是字符串"$BASH_COMMAND"
,因此展开后它等同于:'"$BASH_COMMAND"'
...并且没有该名称的命令,因此您会得到一个错误。
(实际上,unix 文件名中允许使用引号和美元符号,因此您可以命名一个脚本并将其放在
PATH
中的某个位置,然后 将 是一个有效的命令名称。我不特别推荐这样做。)eval "$BASH_COMMAND"
这个比较复杂。
BASH_COMMAND
的值是字符串eval "$BASH_COMMAND"
,所以展开后相当于:eval 'eval "$BASH_COMMAND"'
但是
eval
命令所做的是将其参数 运行 作为 shell 命令,包括所有通常的解析。所以,它 运行 是命令:eval "$BASH_COMMAND"
...再次扩展
$BASH_COMMAND
,导致:eval 'eval "$BASH_COMMAND"'
...这使得
eval
命令解析并且 运行:eval "$BASH_COMMAND"
...这个循环永远持续下去。或者更确切地说,它最终 运行 耗尽了一些资源(可能是堆栈 space),因为它试图跟踪这个不断扩展的东西。显然这会导致处理不当的崩溃。
但无论细节如何,该命令都不可能起作用。它要求 shell 执行无限系列任务,并且无法成功结束。