为什么默认情况下仍然启用 bash 历史替换?

Mik*_*nen 18 bash history-expansion

有人知道为什么 bash 仍然默认启用历史替换吗?我的.bashrc已经包含set +H很多年了,但其他一些人仍然被这个功能所吸引。

鉴于几乎每个人都使用具有复制粘贴功能的终端,并且使用readline库编译的 bash历史替换在默认情况下仅在交互式 shell 中启用,真的有任何理由拥有该功能吗?即使默认情况下为所有 shell 禁用此功能,也不会破坏现有脚本。

如果你不知道为什么历史替换被破坏,试试这个:

$ set +H # disable feature history substitution
$ echo "WTF???!?!!?"
WTF???!?!!?
$ set -H # enable feature history substitution
$ echo "WTF???!?!!?"
echo WTF???echo WTF???!?!!?
WTF???echo WTF???!?!!?
Run Code Online (Sandbox Code Playgroud)

(显然,如果默认情况下所有脚本都禁用该功能,并且存在一个功能可以在执行之前验证结果,则该功能存在重大问题:shopt -s histverify。)

也可以看看:

Kus*_*nda 32

如果您已经熟悉bash,那么处理历史替换模式并不比处理任何其他对这个 shell 特殊的字符更容易咬你。但是,如果不熟悉 shell 或者只是从未使用过它的历史替换功能,那么当看似无害的未引用或双引号字符串触发它时,显然会感到惊讶。

在启用历史替换的交互式 shell 中,该!字符的特殊性与该字符的特殊性几乎相同$,即无处不在,除非使用\单引号字符串或在单引号字符串中进行转义。

$通过相反,历史替换不会在此处文档中扩展,并且由于它们是面向行的,因此它们还会 发生在替换属于未引用上下文或双引号上下文的行(单独扫描时在该行中) . 有关详细信息,请参阅此错误报告

在非交互式 shell(脚本)中禁用历史替换是因为那里不需要 shell 的命令历史功能,而不是因为该功能有“主要问题”。在脚本中,将每个命令保存为$HISTFILE没有意义,历史替换同样不是您希望在脚本中依赖的东西。

是否应该在交互式 shell 中默认启用它是有争议的(尽管我并不完全相信这里的辩论对bash开发人员来说很重要)。你似乎认为大多数bash用户都遇到了历史扩展的问题,但你我谁都不知道使用它们有多普遍。

Unix shell 允许修改 shell 的行为以适应个人的需要和品味。如果您想关闭所有交互式 shell 的历史替换,请继续执行您set +H~/.bashrc文件中使用的操作,或游说bash开发人员更改默认设置(我相信,这会让更多人感到不安和困惑,而不是帮助)。

  • 对。问题实际上根本不在于历史替换,而在于 Bash 中的双“引号”实际上并不是其他语言使用该术语的意义上的引号,而是像一种特殊的括号一样工作。@MikkoRantalainen,养成一种习惯,将您不希望 Bash 以任何特殊方式解释的任何内容放在 _single_ 引号中! (8认同)
  • @leftaroundabout 这取决于您的解释是什么意思。大多数语言将字符串中的控制字符解释为输出(但当然,与在 shell 中混洗字符串时的方式不同)。Perl 的引用规则也很像 shell 的(变量插值)。与任何编程语言一样,如果人们能够记住当前使用的语言是有帮助的。 (5认同)
  • “_我的观点是 ! 很少使用 **特殊** 字符_”我会说这是相反的...... `!` 很少用作 **正常** 字符 - 与 WTF 相呼应– 被抓到的人数远远超过仍然用它来代替历史的人数。 (5认同)
  • -1 将责任转移到不正确的引用上。由于`!` 对*大多数* 类Bourne 的shell 而言*不是* 特殊,在`bash` 脚本中也不是,因此人们可以通过许多途径合理地了解到`"$my_var some text!!"` 将扩展` $my_var` 而不是 `!!`。我熟悉了 `busybox ash` 上类似 Bourne 的 shell,我第一次遇到 `bash` 历史替换*是*当我试图在交互式 shell 中做一些快速的单行时,我被它咬了。精通 Bourne-like shell 的可移植性和脚本使用的人在使用 `bash` 时通常至少被它咬过一次。 (3认同)
  • @MikkoRantalainen 您似乎认为历史替换不是大多数`bash` 用户正在使用的东西。我认为我们中的任何一个都不知道它有多普遍。我建议,如果你对此有强烈的感受,你可以向 `bash` 邮件列表提交一个特性/错误请求。见 https://savannah.gnu.org/mail/?group=bash (2认同)

Joh*_*éen 9

历史替换很有用。以

% make-me-a-sandwich
make-me-a-sandwich: Permission denied
% sudo !!
Ok.
Run Code Online (Sandbox Code Playgroud)

  • 所以?如果你觉得它有用,你可以在你的 `.bashrc` 中启用它。 (3认同)
  • https://xkcd.com/149/ (3认同)
  • @Barmar,如果您发现它没有用,您可以禁用它。有趣的是对称是如何工作的。 (3认同)
  • @hobbs 如果你不知道它存在,你怎么知道禁用它? (3认同)
  • 这个答案很好地解释了该功能有用的一个原因。我认为 OP 想了解*为什么*这种有用性*足以*证明这种行为是合理的,即使 OP(和其他人,例如在此 stackexchange 上询问几个相关问题的人)发现这种行为令人惊讶/出乎意料。 (2认同)
  • ctrl-P ctrl-A 并输入 `sudo` 的作用相同,主要区别在于您可以看到自己在做什么。并且无需记住具有损坏实现的特殊功能。 (2认同)

mtr*_*eur 4

社会/文化惰性。

这个问题属于人类如何工作的问题空间,所以我将从这个角度回答,而不对该功能是否应该默认启用提出任何意见。

首先,为了确保你理解对方,请考虑一下,你对不得不特意关闭该功能所感到的烦恼,就是如果他们不得不特意打开该功能也会感到的烦恼该功能。

结合上述情况,再加上有足够多的bash用户确实使用该功能,默认情况下删除或关闭它的建议遭到了那些已经习惯默认情况下存在的人的抵制。

此外,bash它是许多人的默认 shell(不仅仅是默认登录或系统 shell 意义上,而且在心理意义上)。如果您的 shell 引用的参考框架是bash,如果这是您首先学习的 shell,那么它!是一个特殊的 shell 字符这一事实对您来说会感觉自然且自动(或者至少,当您第一次学习它时,它将只是shell 的方式只是众多怪癖中可以接受的一个)。

如果你想一想,很多用户可能会在积极的bash上下文中遇到历史替换语法:他们读到它或有人向他们展示它,并且当他们第一次学习时,他们看到它可能的用处。bash

它只是来自其他类似 Bourne 的 shell 的外围世界,你会被它的!特殊性所困扰从而倾向于消极地看待它:因为如果你习惯了从未有过该功能的 shell,那么你的第一个当你试图匆忙完成某件事时,它就会让你陷入困境。

TL;DR:大多数用户可能不太关心默认值是什么,有些用户喜欢该功能,并且已经具有这种功能的强大优势,而且还没有足够多的人积极反对该功能克服这一点。

  • 不,不仅仅是来自其他贝壳时。我在“bash”中已经知道这个功能很多年了,但仍然感到惊讶,因为单引号[并不总是有效](https://unix.stackexchange.com/questions/390931/bash-history-expansion-由于 `bash` 实现被破坏,所以在 `!` 上使用了 inside-single-quotes-after-a-double-quote-inside-the-sam)。 (2认同)