为什么默认情况下仍启用bash历史记录替换?[关闭]


17

有人知道为什么默认情况下bash仍启用历史记录替换吗?.bashrc已经加入set +H了很多年,但其他一些人仍被该功能所困扰。

鉴于几乎每个人都在使用具有复制粘贴功能的终端,并且使用readline库编译的bash 默认情况下仅在交互式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???!?!!?

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

也可以看看:


16
您似乎认为人们不使用历史替代。我每天都使用它。我发现比起重新调用和编辑命令来,跟进ls -l foo/bar/baz/weeble.cpp起来更快less !$
马丁·邦纳

2
@MartinBonner因此,您可以启用它。问题是关于为什么默认启用它,而不是为什么它仍然存在。
Barmar

5
@Barmar:好的。但是我的观点是对提出该问题的假设提出质疑。
马丁·邦纳

5
如果我们遵循您的推理,则默认情况下应禁用任何需要转义或引用的内容。为什么我需要转义或引用包含的URL &?为什么我需要转义或引用包含一个文件名??有些用户界面认为这是一个问题。
jcaron

3
!$每天使用几次,也!!经常使用。我必须承认我没有使用其他历史记录替换,但是如果我多年来使用的Shell的默认行为突然改变,我肯定会很不满意。
jcaron

Answers:


32

如果您已经熟悉bash,那么处理历史记录替换模式与处理此Shell特殊的任何其他字符相比,咬住您的可能性不大。但是,如果一个人不熟悉shell或从未使用过它的历史记录替换功能,那么当看似无害的未加引号或双引号的字符串触发它时,显然会感到惊讶。

在启用了历史替换的交互式外壳中,!字符的特殊性与字符的特殊性几乎相同$,即无处不在,除非使用\或用单引号引起来。

$直通相反,历史替换在here-documents中不会扩展,并且由于它们是面向行的,因此它们还将 在替换位于未加引号的上下文或双引号的上下文中的行上发生(在单独扫描的该行中) 。有关更多信息,请参见此错误报告

在非交互式外壳程序(脚本)中禁用了历史记录替换,因为在那里不需要外壳程序的命令历史记录功能,这不是因为该功能存在“重大问题”。在脚本中,将每个命令都保存为$HISTFILE没有意义,并且历史记录替换同样不是您想要在脚本中依赖的内容。

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

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


2
@MikkoRantalainen您似乎认为历史替换并不是大多数bash用户使用的东西。我不认为我们两个人都知道这种情况有多普遍。如果您对此有强烈的建议,建议您向bash邮件列表提交功能/错误请求。参见savannah.gnu.org/mail/?group=bash
库萨兰达

8
对。问题实际上根本不是关于历史的替换,而是关于Bash中的双“引号”并不是真正意义上的引号,在其他语言使用该术语的意义上,而是像一种特殊的括号一样工作。@MikkoRantalainen,养成一种习惯,将您不希望Bash以任何特殊方式解释的任何内容放在引号中!
leftaboutabout

5
@leftaroundabout这取决于您所解释的意思。大多数语言将字符串中的控制字符解释为输出(但被授予,但只是在将字符串改组时,其方式与Shell中的方式不同)。Perl的引用规则还非常类似于shell的(可变插值)。与任何编程语言,它帮助,如果人们能够记住什么语言一个目前正在英寸
Kusalananda

5
我的意思是!很少使用特殊字符 ”我想说的是相反的话……这种字符!很少用作普通字符-除了回荡WTF之外-被困的人数远远超过了仍然用它代替历史的人数。
TripeHound18年

3
-1用于将责备转移到不正确的报价上。既然!不是特别的大多数类似Bourne外壳,也没有bash脚本,也都是人们可以合理地了解到,许多路径"$my_var some text!!"将扩大$my_var,但不是!!。我对上的Bourne式shell很熟悉busybox ash,而我第一次遇到bash历史替换在尝试在交互式shell中快速编写单行代码时被它咬住了。精通Bourne式外壳的可移植性和脚本编写用途的人员在使用时经常被它咬至少一次bash
mtraceur '18 -4-9

9

历史记录替换很有用。举个例子

% make-me-a-sandwich
make-me-a-sandwich: Permission denied
% sudo !!
Ok.

2
所以?如果您觉得有用,可以在中启用它.bashrc
Barmar


3
@Barmar,如果您发现它无用,则可以将其禁用。有趣的是对称如何工作。
hobbs

3
@hobbs如果您不知道它存在,您怎么知道禁用它?
Barmar

2
这个答案很好地解释了该功能有用的一个原因。我认为OP希望理解为什么这种有用性足以证明这种行为的合理性,即使OP(以及其他人,例如在此stackexchange上问一些相关问题的人)发现这种行为令人惊讶/出乎意料。
mtraceur '18

4

社会/文化惯性。

这个问题是在“人类如何工作”的问题空间中进行的,因此我将从这个角度回答,而不会对功能默认情况下是否启用提出任何意见。

首先,要确保您了解另一面,请考虑一下您不得不退出以关闭功能所带来的烦恼,是他们必须离开时才能打开的烦恼功能。

将以上内容与足够的bash用户使用该功能这一事实相结合,默认情况下已经对它感到满意的人会遇到抵制的建议,即删除或默认关闭它的建议。

另外,bash是许多人默认的shell(不只是在默认的登录或系统shell意义,但在心理意义上的)。如果您的shell引用参考框架是bash,如果这是您首先学习的shell,那么对于您来说,这!是一个特殊的shell字符这一事实将是自然而自然的(或者至少在您初次学习时,它只是其中的一部分)外壳的方式,只是其中的一个怪癖)。

而且,如果您考虑一下,很多bash用户可能会在积极的环境中遇到历史替换语法:他们阅读了它,或者有人向他们展示了它,并且在初次学习时看到了它的可能用处bash

它仅来自其他类似Bourne的shell的外围世界,您会!被特殊的事物所咬住因此倾向于以负面的态度看待它:因为如果您习惯了没有该功能的shell,那么您的第一个当您试图匆忙完成某件事时,它就会暴露在您的眼前。

TL; DR:大多数用户可能不太在意这两种方式的默认设置,有些用户喜欢该功能,并且已经拥有这种功能的强大优势,并且没有足够的人积极地反对该功能来克服那个。


2
不,不仅是来自其他外壳的情况。我知道这个功能了多年bash,仍然获得措手不及咬伤,单报价并不总是有效!,因为破碎的bash实施。
Philippos '18

@Philippos这太可怕了(嗯,不完全是可怕的……但是某种令人沮丧的消极情绪)。感谢您指出了这一点。一旦我想到了将其集成的好方法,稍后我将尝试重新访问该答案以将您的观点转化为我的答案。
mtraceur

2

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

因为有很多人在使用它,并且使用交互式bash shell的人们可能应该知道避免问题的规则,并且通常会发现它的帮助远大于伤害。

我的.bashrc包含set + H已有很多年了,但是其他一些人仍然被该功能所困扰。

因此,这是您不使用的功能,并不意味着大多数用户不使用它。您可以要求更改默认值,但您必须查看A)关心的人的比例,以及B)偏爱它的人的比例。人民群众关心不喜欢它可能已经拥有它禁用。当他们在新计算机上获得帐户时,对其进行更改将很有帮助。人们关心不喜欢它会对他们使用他们在未来获得每台电脑,每个帐户上更新自己的设置。

鉴于几乎每个人都在使用具有复制粘贴功能的终端

我认为这是一个比较笨拙的选择...

真的有任何理由要使用此功能吗?即使默认情况下所有外壳程序都禁用了此脚本,也不会破坏现有脚本。

是的,人们发现它很有用。假设您以前只能起床并更改频道,那么使用遥控器有什么用?

(很明显,如果默认情况下对所有脚本禁用此功能,并且存在在执行之前验证结果的功能,则该功能会存在严重问题:shopt -s histverify。)

历史记录在脚本中并没有真正意义,但更重要的是,它可能会导致安全问题。在您的情况下,可以通过使用单引号来避免出现此问题。我不记得这曾经对我造成问题,所以我不知道你怎么能说它有“重大问题”。这是否给您造成了实际问题,还是让您讨厌在新计算机上设置默认值?

如果您确实想赚钱,我看不出它与必须转义或使用单引号有什么不同:

$ echo "Give me $50 or the cat gets it"
Give me $0 or the cat gets it

2
参见相关问题(右列);大多数问题都是无意中触及此功能,并假定外壳已损坏。由于我不小心使用了导致错误输出的字符序列,因此我很久以前就亲自了解了此功能。我会一直保存的shopt -s histverify,但是是不是默认。此外,很难自行找出原因,因为错误消息是含糊的(“未找到事件”)并且触发它的字符序列很难用Google搜索。
米科·兰塔莱宁

1
人们真正被此功能所咬,是因为“通用” shell语法功能(例如$在内部特殊)"..."是人们了解shell的第一件事,而在!内部"..."(但仅在交互模式下)特殊的事实鲜为人知,通常没有立即/突出地讲授,并且是bash特定的。此外,类似Bourne的外壳在脚本内文本和交互式外壳上的文本之间大多具有对称性,因此您通常可以将一种文本与另一种文本相互复制并保持相同的功能-并且此功能可以创建唯一的例外之一。
mtraceur '18

1
我没有看到与必须转义或始终使用单引号 True的情况有什么不同zsh,当单引号!始终有效时,而对于bash在实现产生意外结果的情况下,则不行。您说,我们应该了解规则,好吧,您知道该关联规则吗?
Philippos '18
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.