脚本中是否禁用了历史记录扩展?


9

我了解以下错误是由于!用于历史记录扩展而导致的:

$ echo "Hello!Tim"
bash: !Tim: event not found

但是,如果将命令放入脚本中并运行该脚本,则不会出现问题:

$ cat myscript
echo "Hello!Tim"
$ bash myscript 
Hello!Tim

这是为什么?bash手册中是否提到了原因?


1
简单地说,这是个好问题。做得太好了!
通配符

根据我在这里阅读的内容:gnu.org/software/bash/manual/html_node/History-Interaction.html我相信您需要使用某种shopt修饰符才能使其在脚本中正常工作。我知道这并不是您要找的答案。
jesse_b

用例是什么?您将运行哪种脚本来扩展以前的历史记录?还是会扩展脚本中的先前命令?
杰夫·谢勒

@JeffSchaller,使用正数的脚本中的数字历史记录扩展听起来确实是个坏主意,但我可以轻松想象出!!or或!-2(负/相对历史数字)或类似用例的用法。通常,可以通过其他方法更好地解决它们,但是对于外壳如何工作(以及何时/不需要逃避惊叹!)仍然是一个很好的问题。
通配符

Answers:


12

是的,默认情况下仅对交互式外壳程序启用历史记录扩展。

要为shell脚本启用它,请编写:

set -H

要在交互式shell中禁用它,请输入:

set +H

要确定当前是否启用历史记录扩展,请使用以下代码的某种形式:

case $- in (*H*) echo enabled ;; (*) echo disabled ;; esac

在开始讲授外壳课程时,我广泛地阅读了手册,以尝试确定什么是“交互式外壳”。这是一个漩涡问题,所以让我为您省些麻烦:

外壳有很多选项。当外壳具有控制终端时(或以-i,等等)启动时,这些选项中的一些将以不同的方式初始化。

外壳程序的所有选项都可以单独更改。

当您尝试精确定义“交互式外壳”时,这是一个欺骗性术语。 它实际上只是选项设置的集合。

关于哪些设置使外壳交互或不交互的问题无法回答。它变得荒谬。这与These修斯完全相同的哲学问题。

如果启动交互式外壳程序,但随后禁用历史记录扩展,则使用--noediting标志,设置--norc,关闭expand_aliases等,那么外壳程序在什么意义上是交互式的?或者,何时不再互动?您无法回答这些问题。

事实是,“交互”只是各种外壳选项集合的便捷标签。同样是“非互动式”。一样; 只是一系列行为,每个行为都可以单独更改。

底线:“交互”启动时外壳与“非交互”启动时外壳的行为有所不同。在启动后试图精确定义这些术语是很愚蠢的。只需查看shell的每个选项即可了解其行为。


我忘记了,除了我自己的研究之外,我还在这个站点上广泛地发布了有关它的信息。


谢谢。在手册中,我仅找到的“交互式外壳程序默认情况下启用此选项” set -H。您的推断可能是“默认情况下仅对交互式shell启用历史记录扩展”。
蒂姆(Tim)

@Tim,请参阅其余答案。手册的那句话很滑,试图得到“什么是交互式外壳?”的答案。手册页中的内容就像在圈子里聊天。无处可去。
通配符

您可以说的是,以下代码段将始终向您显示是否在当前Shell中启用了历史记录扩展:case $- in (*H*) echo enabled ;; (*) echo disabled ;; esac
通配符

@Tim,顺便说一句,我不知道您是什么意思,这是我的“推断”,因为那是的明确含义set -H。那就是histexpand选项。
通配符

1
我已经在脚本上尝试过此操作,直到从脚本set -o history验证set -o是否已禁用后,它也才起作用。
Daniel C. Sobral
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.