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

Tim*_*Tim 12 bash command-history shell-script

我了解以下错误是由于!用于历史扩展:

$ echo "Hello!Tim"
bash: !Tim: event not found
Run Code Online (Sandbox Code Playgroud)

但是,如果我将命令放入脚本并运行该脚本,则没有问题:

$ cat myscript
echo "Hello!Tim"
$ bash myscript 
Hello!Tim
Run Code Online (Sandbox Code Playgroud)

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

Wil*_*ard 14

是的,默认情况下仅对交互式 shell 启用历史扩展。

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

set -H
Run Code Online (Sandbox Code Playgroud)

要在交互式 shell 中禁用它,请编写:

set +H
Run Code Online (Sandbox Code Playgroud)

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

case $- in (*H*) echo enabled ;; (*) echo disabled ;; esac
Run Code Online (Sandbox Code Playgroud)

在开始教授 shell 课程时,我广泛地翻阅了手册,试图确定什么是真正的“交互式 shell”。这是一个漩涡问题,所以让我为您省去一些麻烦:

shell 有很多选项。当 shell 有一个控制终端时(或者当以-i, blah blah 等开头时,这些选项中的一些以不同的方式初始化,见下文)。

shell 的所有选项都可以单独更改。

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

关于哪些设置使 shell 交互或不交互的问题是无法回答的;它变得荒谬。这正是与忒修斯之船相同的哲学问题。

如果你启动一个交互式shell,然后禁用历史扩展,使用--noediting标志,设置--norc,关闭expand_aliases等等,那么shell交互式在什么意义上?或者,它何时不再具有交互性?你无法回答这些问题。

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

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


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