$BASH_COMMAND 变量有什么用?

Mal*_*ppa 25 command-line bash environment-variables

根据Bash 手册,环境变量BASH_COMMAND包含

当前正在执行或即将执行的命令,除非 shell 作为陷阱的结果正在执行命令,在这种情况下,它是在陷阱发生时正在执行的命令。

把那个陷阱角落放在一边,如果我理解正确的话,这意味着当我执行命令时,变量BASH_COMMAND包含该命令。这不是绝对清楚地表明变量是否是在执行命令后复位(也就是,只有avaialble命令正在运行,但不是之后),尽管有人可能会认为,既然是“命令当前正在执行或即将执行的” ,不是刚刚执行的命令。

但是让我们检查一下:

$ set | grep BASH_COMMAND=
$ 
Run Code Online (Sandbox Code Playgroud)

空的。我本来希望看到BASH_COMMAND='set | grep BASH_COMMAND='或者只是看到BASH_COMMAND='set',但空虚让我感到惊讶。

让我们试试别的:

$ echo $BASH_COMMAND
echo $BASH_COMMAND
$ 
Run Code Online (Sandbox Code Playgroud)

嗯,这是有道理的。我执行命令echo $BASH_COMMAND,因此变量BASH_COMMAND包含字符串echo $BASH_COMMAND。为什么这次有效,而之前无效?

让我们再做set一次:

$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Run Code Online (Sandbox Code Playgroud)

所以等等。它在我执行该echo命令时设置的,之后没有取消设置。但是当我set再次执行时,BASH_COMMAND 没有设置为set命令。无论我在set这里执行命令的频率如何,结果都保持不变。那么,是否在执行echo时设置了变量,但在执行时没有设置set?让我们来看看。

$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Run Code Online (Sandbox Code Playgroud)

什么?所以变量是在我执行时设置的echo $BASH_COMMAND,但不是在我执行时echo Hello AskUbuntu?现在区别在哪里?是否仅在当前命令本身实际强制 shell 评估变量时设置变量?让我们尝试不同的东西。这次也许是一些外部命令,而不是 bash 内置命令,以进行更改。

$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$
Run Code Online (Sandbox Code Playgroud)

嗯,好的...再次,变量被设置。那么我目前的猜测是否正确?变量是否仅在必须评估时才设置?为什么?为什么?出于性能原因?让我们再试一次。我们将尝试$BASH_COMMAND在文件中grep for ,因为$BASH_COMMAND应该包含一个grep命令,所以grep应该 grep 为该grep命令(即,为它自己)。所以让我们制作一个合适的文件:

$ echo -e "1 foo\n2 grep\n3 bar\n4 grep \$BASH_COMMAND tmp" > tmp
$ grep $BASH_COMMAND tmp
grep: $BASH_COMMAND: No such file or directory
tmp:2 grep                                      <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the word "grep" is RED
tmp:2 grep                                      <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp                    <-- here, the word "grep" is RED
$ set | grep BASH_COMMAND=
BASH_COMMAND='grep --color=auto $BASH_COMMAND tmp'
$
Run Code Online (Sandbox Code Playgroud)

好吧,有意思。命令grep $BASH_COMMAND tmp被扩展为grep grep $BASH_COMMAND tmp tmp(当然,变量只被扩展了一次),所以我grep$BASH_COMMAND不存在的文件中搜索了一次,在文件中搜索了两次tmp

Q1:我目前的假设是否正确:

  • BASH_COMMAND仅在命令尝试对其进行实际评估时设置;和
  • 执行命令后它不会取消设置,即使描述可能会让我们相信?

Q2:如果是,为什么?表现?如果不是,上述命令序列中的行为还能如何解释?

Q3:最后,有没有什么场景可以真正有意义地使用这个变量?我实际上是在尝试使用它$PROMPT_COMMAND来分析正在执行的命令(并根据它做一些事情),但我不能,因为只要在我的 内$PROMPT_COMMAND,我执行一个命令来查看变量$BASH_COMMAND,变量获取设置为该命令。即使我MYVARIABLE=$BASH_COMMAND在 , 的开头做对$PROMPT_COMMAND,然后MYVARIABLE包含字符串MYVARIABLE=$BASH_COMMAND,因为赋值也是命令。(这个问题不是关于我如何在$PROMPT_COMMAND执行中获取当前命令。我知道还有其他方法。)

这有点像海森堡的测不准原理。仅仅通过观察变量,我就改变了它。

Dmi*_*rov 15

回答第三个问题:当然可以按照 Bash 手册中明确提示的方式有意义地使用它 - 在陷阱中,例如:

$ trap 'echo ‘$BASH_COMMAND’ failed with error code $?' ERR
$ fgfdjsa
fgfdjsa: command not found
‘fgfdjsa’ failed with error code 127
$ cat /etc/fgfdjsa
cat: /etc/fgfdjsa: No such file or directory
‘cat /etc/fgfdjsa’ failed with error code 1
Run Code Online (Sandbox Code Playgroud)


zwe*_*ets 6

既然已经回答了 Q3(在我看来BASH_COMMAND是正确的:在陷阱中很有用,而在其他任何地方几乎都没有),让我们试一试 Q1 和 Q2。

Q1 的答案是:你的假设的正确性是不可判定的。由于他们询问未指明的行为,因此无法确定这两个要点的真实性。根据其规范,在BASH_COMMAND该命令的执行期间,将 的值设置为该命令的文本。规范没有说明在任何其他情况下它的值必须是什么,即当没有命令被执行时。它可能有任何价值或根本没有价值。

问题 2 的答案“如果不是,上述命令序列中的行为还能如何解释?” 然后在逻辑上遵循(如果有点迂腐):这是由值BASH_COMMAND未定义的事实来解释的。由于它的值是未定义的,它可以有任何值,这正是序列所显示的。

后记

有一点我认为你确实在规范中遇到了一个情有独钟。这是你说的地方:

即使当我在 $PROMPT_COMMAND 的开头执行 MYVARIABLE=$BASH_COMMAND 时,MYVARIABLE 也包含字符串 MYVARIABLE=$BASH_COMMAND,因为赋值也是命令

我阅读 bash 手册页的方式,斜体部分是不正确的。该部分SIMPLE COMMAND EXPANSION解释了如何首先将命令行上的变量赋值放在一边,然后

如果没有命令名称结果 [换句话说,只有变量赋值],则变量赋值会影响当前的 shell 环境。

这向我表明变量赋值不是命令(因此不会出现在 中BASH_COMMAND),就像在其他编程语言中一样。这也可以解释为什么BASH_COMMAND=set的输出中没有一行setset本质上是变量赋值的句法“标记”。

OTOH,在该部分的最后一段中说

如果扩展后还有命令名,则执行如下所述。否则,命令退出。

... 否则暗示,变量赋值也是命令。