问题描述
根据Bash manual,环境变量BASH_COMMAND
包含
The command currently being executed or about to be executed, unless the shell is executing a command as the result of a trap, in which case it is the command executing at the time of the trap.
撇开陷阱的情况,如果我理解正确,这意味着当我执行命令时,变量BASH_COMMAND
包含该命令。尽管可能有人争辩说,因为它是“当前正在执行或将要执行的命令”,但仍不确定是否在执行命令后未设置该变量(即仅在命令运行时可用)。 ,不是刚刚执行的命令。
但是让我们检查一下:
$ set | grep BASH_COMMAND=
$
空的我本来希望看到BASH_COMMAND='set | grep BASH_COMMAND='
或也许只是BASH_COMMAND='set'
,但空虚使我感到惊讶。
让我们尝试其他方法:
$ echo $BASH_COMMAND
echo $BASH_COMMAND
$
嗯,这很有道理。我执行命令echo $BASH_COMMAND
,因此变量BASH_COMMAND
包含字符串echo $BASH_COMMAND
。为什么这次这次有效,但以前却没有呢?
让我们再次执行set
的操作:
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
等一下它是在我执行该echo
命令时设置的,此后并没有取消设置。但是,当我再次执行set
时,未将BASH_COMMAND
设置为set
命令。无论我在这里执行set
命令的频率如何,结果都保持不变。那么,在执行echo
时是否设置了变量,而在执行set
时没有设置?让我们来看看。
$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
什么?所以变量是在我执行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'
$
嗯,好的。。。再次设置变量。那么我目前的猜测正确吗?仅在需要评估变量时设置变量吗?为什么?为什么?出于性能原因?让我们再尝试一次。我们将尝试在文件中grep $BASH_COMMAND
,并且由于$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'
$
好吧,有趣。命令grep $BASH_COMMAND tmp
扩展为grep grep $BASH_COMMAND tmp tmp
(当然,变量仅扩展了一次),因此我为grep
进行了grep操作,一次是在不存在的文件$BASH_COMMAND
中,一次是在文件tmp
中。
问题1:我目前的假设是否正确:
-
BASH_COMMAND
仅在命令尝试对其求值时才置位。和 -
即使描述可能使我们相信,在执行命令后仍未设置它?
问题2:如果可以,为什么?性能?如果否,那么如何解释以上命令序列中的行为?
问题3:最后,在任何情况下都可以实际使用此变量吗?我实际上是试图在$PROMPT_COMMAND
中使用它来分析正在执行的命令(并根据它做一些事情),但是我不能,因为在$PROMPT_COMMAND
中,我立即执行了一个命令来查看变量$BASH_COMMAND
,该变量将获得该命令的设置。即使当我在$PROMPT_COMMAND
的开头直接执行MYVARIABLE=$BASH_COMMAND
时,MYVARIABLE
也包含字符串MYVARIABLE=$BASH_COMMAND
,因为赋值也是命令。 (此问题与我如何在$PROMPT_COMMAND
执行中如何获取当前命令无关。我知道还有其他方法。)
这有点像海森堡的不确定性原理。只需观察变量,即可对其进行更改。
最佳办法
回答第三个问题:当然,它可以按照Bash手册明确提示的方式进行有意义的使用-陷阱,例如。 G。:
$ 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
次佳办法
现在已经回答了Q3(我认为正确的是:BASH_COMMAND
在陷阱中有用,几乎在其他任何地方都没有用),现在让我们来看看Q1和Q2。
Q1的答案是:您的假设的正确性尚不确定。当他们要问未指明的行为时,这两个要点都不成立。根据其指定,在该命令的执行期间,将BASH_COMMAND
的值设置为该命令的文本。规范没有说明在任何其他情况下(即没有命令执行时)其值必须是什么。它可以具有任何值或根本没有任何值。
问题2的答案:“否,那么如何解释以上命令序列中的行为?”然后从逻辑上讲(如果有些书呆子):由以下事实解释:BASH_COMMAND
的值未定义。由于其值是不确定的,因此它可以具有任何值,这正是序列显示的值。
后记
我认为您确实在规范中遇到了一个弱点。在这里你说:
Even when I do MYVARIABLE=$BASH_COMMAND right at the beginning of my $PROMPT_COMMAND, then MYVARIABLE contains the string MYVARIABLE=$BASH_COMMAND, because an assignment is a command too.
我阅读bash手册页的方式不是斜体。 SIMPLE COMMAND EXPANSION
部分说明了如何首先在命令行中保留变量分配,然后再保留
If no command name results [in other words, there were only variable assignments], the variable assignments affect the current shell environment.
这向我表明,变量赋值不是命令(因此免于出现在BASH_COMMAND
中),就像其他编程语言一样。然后,这也可以解释为什么set
的输出中没有行BASH_COMMAND=set
,而set
本质上是用于变量分配的语法’marker’。
OTOH,在该部分的最后一段中说
If there is a command name left after expansion, execution proceeds as described below. Otherwise, the command exits.
…表示不正确,变量分配也是命令。