!
)的http url。例如:curl -v "http://example.org/!287s87asdjh2/somepath/someresource"
bash: ... event not found。
这是怎么回事?逃脱感叹号的正确语法是什么?
#1 楼
感叹号是bash历史扩展中的一部分。要使用它,您需要将其括在单引号中(例如:'http://example.org/!132'
),或者直接在字符前面使用反斜杠(\
)将其转义(例如:"http://example.org/\!132"
)。在感叹号阻止历史扩展之前使用反斜杠,但是在这种情况下不会删除反斜杠。因此,最好使用单引号,这样就不会在URL上将文字反斜杠传递给curl
。评论
实际上,“ http://example.org/\!132”在扩展时没有解释反斜杠(我相信是POSIX合规性原因)。
–克里斯唐(Chris Down)
2012年3月3日19:14
@ChrisDown,我试图澄清这是文本中的第二个选项。感谢您指出混淆的可能。
–丹尼尔·皮特曼(Daniel Pittman)
2012年3月3日在22:30
记录:尝试转义“!”不是可移植的。最佳做法建议是始终用单引号(!)引号!相关信息:“ ^”(脱字符号),是非字符,需要引用才能实现可移植性。最后,“!”不应在if语句中使用;尽可能使用它作为参数进行测试(同样由于Solaris / bin / sh)。
–尼古拉斯·威尔逊(Nicholas Wilson)
2012年10月18日上午10:31
只有单引号对我有用。 zsh仍在解释\!和双引号。
–orkoden
2014年5月21日在16:29
在Solaris(旧的XPG4以前的旧外壳)上,“ ^”是|的别名。并用于创建管道。如果您要向客户发送脚本,但不确定他们将在哪个shell中运行脚本,则必须对它们全部进行测试!
–尼古拉斯·威尔逊(Nicholas Wilson)
18年1月16日在9:47
#2 楼
除了Daniel给出的答案外,如果您不使用set +H
,也可以完全关闭历史记录扩展。评论
整天关闭历史记录扩展是我整天听到的最好建议!当有更好的替代方法(使用Ctrl-R进行增量历史搜索)时,历史扩展会很危险,而且会造成拜占庭式的麻烦。这些替代方法可以预览和编辑命令,因此您不会盲目地使用命令!-14,尽管您原来在!-12糟糕,恰好是rm -rf *。注意安全。禁用历史记录扩展!避免!
– aculich
2012年6月6日在1:09
最大的答案:历史扩展是巨大的安全风险!它可以用来通过特制的URL攻击Unix。
– dan
2015年6月15日7:30
@aculich,或仅使用POSIX指定的命令fc -14。但是,确实可以在不启用历史记录扩展的情况下执行此操作。我个人使用!$和!vi和sudo !!甚至git add!vi:$经常足以保证启用历史记录扩展。
–通配符
18年1月16日在5:02
我想将其添加到我的Shell RC文件中。我只把它当作整洁的“把戏”
– TonyH
19年8月22日在14:02
另外,IMO还提供更多描述性语法来关闭bash历史记录扩展:set + o histexpand;另请参见superuser.com/a/133782
–ssc
20年6月28日在10:15
#3 楼
我个人会用单引号引起来,但出于完整性考虑,由于它是一个URL,因此您可以将!
编码为%21
,例如curl -v http://example.org/%21132
。#4 楼
这也可以做到,因为bash将相邻的字符串连接在一起,所以可以工作。curl -v "http://example.org/"'!'"287s87asdjh2/somepath/someresource"
curl -v "http://example.org/"\!"287s87asdjh2/somepath/someresource"
当您还有其他需要外壳扩展的内容时,此方法特别有用,因此您不能在整个字符串中使用单引号:
curl -v 'http://example.org/!'"287s87asdjh2/${basepath}/someresource"
命令行提示符中的历史记录扩展。
所以这可能是提示符中的问题,但不是Shell脚本文件中的问题。
评论
有很多方法可以使Unix命令和英语句子使用比他们需要的字符更多的字符,并使它们比需要的字符更加混乱。这比第一个/接受的/投票最高的答案(即将整个URL放在单引号中)有什么优势?
– G-Man说“恢复莫妮卡”
15年6月15日在7:10
@ G-Man:它告诉了另一种构造bash参数的方法。我不知道这种方法。学习新东西没错。
– Sahil Singh
16年7月6日在12:30
@SahilSingh这是新的吗?它连接三个字符串,两个字符串用双引号引起来,一个字符串用单引号引起来。这里没有嵌套。
–拉斐尔
17 Mar 10 '17 at 6:44
@ G-Man并不明显,当您将2个字符串彼此相邻放置时,它们会串联在一起。 printf(“ hello”“ world”)也可以在c中工作,但是printf(“ hello”'w')不能工作,所以您知道知道bash可以容纳这样的表达式对我来说是新的,但是我同意效用来看,这并不优越。我喜欢这个答案,马克·舒斯特也一样。
– Sahil Singh
17 Mar 10 '17 at 7:06
@ G-Man当确实要在同一字符串中进行其他字符串扩展时,它也很有用。这是分离两种类型的报价行为的简便方法。
– WAF
17年5月1日在15:09
#5 楼
我遇到了同样的问题,我的简单解决方案是使用变量:E=!
curl -v "http://example.org/${E}287s87asdjh2/somepath/someresource"
这里的简单之处在于(1)它可以在shell和命令之间移植(2)不需要知道转义语法和ASCII代码。
#6 楼
从Bash 4.3开始,您现在可以使用双引号来引用历史记录扩展字符:$ bash --version
GNU bash, version 4.3...
[...]
$ echo "Hello World!"
Hello World!
评论
这在echo之外不起作用,echo似乎单独处理此问题
– phil 294
17年9月30日在12:04
@Blauhirn这与echo无关,与引用和正在运行的bash版本无关。
– Flimm
17-10-1在13:38
这个答案是错误的,应该删除。您的bash版本与爆炸没有得到扩展没有关系,这是由于在您的示例中!后面跟着“行尾”,这可以防止外壳尝试扩展外壳。尝试echo“!Hello World”,您将看到bash会以bash回复:!Hello:事件未找到。有关更多详细信息,请参见手册
–don_crissti
17/12/19在16:47
#7 楼
对于在Windows中使用git bash的用户,@ DanielPittman可接受的答案有效。但是,应将反斜杠(\)替换为正斜杠(/)。例如,在unix中,它看起来像这样:重点放在授权标头部分中的正斜杠上)
curl https://abc.com/services -H 'Authorization: Bearer 111A80BBZZCnS\!ZR412543s'
评论
这没有多大意义。您将论点单引号括起来,因此无论是否包含斜杠,感叹号都不会导致历史扩展。
–通配符
18年1月16日在5:03
哦,对了。我之所以仅发布此答案,是因为当我使用Daniel的答案(使用反斜杠)时,会弹出一个错误。
– SamuelDev
18年1月16日在5:12
评论
解决于bash 4.4+