Bash [[ 测试,引用变量

5

我希望决定是否在Bash的[[测试中始终省略变量的引号。我解释man页面,认为这样做是可以的,而且不会有任何损失。


我设计了这个简单的“测试”来验证我的想法和“预期行为”,但它可能毫无意义,请看一下:

x='1 == 2 &&'
if [[ $x == '1 == 2 &&' ]]; then
    echo yes
else
    echo no
fi

请注意,我并不是在这样写:

x='1 == 2 &&'
if [[ "$x" == '1 == 2 &&' ]]; then
    echo yes
else
    echo no
fi

迄今为止,出于一致性的考虑,我总是采用这种风格。


[[测试中,总是省略变量周围的引号安全吗?

我正在尝试学习Bash,并试图养成良好的习惯、良好的风格和正确性。


8
注意:在 == 和 != 的右侧,如果未加引号,则它被视为模式而不是字符串。因此,如果 x="Now is"y="[nN]ow*",则 [[ $x == "$y" ]] 为假,而 [[ $x == $y ]] 为真。这可能会在某些情况下对你有影响。 - William
非常好的观点!谢谢!!我确实只是指左边...(我应该明确说明)。不过很高兴学到了你的见解。 - Robottinosino
2个回答

9
记住的关键是,在模式匹配上下文中,引号和转义始终使其内容变成字面量。在[[内部的==的左侧引用从不必要,只有右侧被解释为模式。如果您想要一个字面匹配并避免变量内的模式元字符的解释,则需要在右侧进行引用。
换句话说,[ "$x" = "$x" ][[ $x == "$x" ]] 大多数情况下是等价的,在Bash中当然应该优先使用后者。
一个快速提示:将[[ ]]复合命令的运算符视为与其他控制运算符(例如elifdo;;;;&)具有相同语法是很重要的(尽管在手册中它们属于自己的类别)。它们实际上是复合命令的各个部分的分隔符,这就是它们实现看似神奇的特性(如能够短路扩展)的方式。这应该有助于澄清[[的许多行为,以及它与算术运算符等的区别。
更多示例:http://mywiki.wooledge.org/BashFAQ/031#Theory

您的输入总是非常受欢迎!为什么“后者”更可取?使用那里的功能?我不明白引用左侧会如何“不必要地”造成任何伤害...是否存在某种情况会造成伤害? - Robottinosino
@Robottinosino 我不知道有没有这样的规定。因为在那种情况下引号从来都不是必需的,所以不包括它们可以让这个事实更加明显。如果你随机或者甚至过度地使用引号,很容易变得混淆,因为人们会看到一些地方被引用了,而其他地方则没有。有些情况下,由于各种原因,您真的不想引用。如果随意引用,就不清楚哪些情况下是可选的,哪些情况下省略了一个真正的效果。有时候,明确意味着允许隐含的事情一致发生。 - ormaaj
我对这个说法并不完全认同:“有时候明确意味着允许隐含的事情一直发生”,但基于我对你的经验和总体上的帮助性的尊重,我还是会更倾向于接受你的答案,这真的很激励人心。 - Robottinosino
1
这不是一门正常的、理智的语言。在普通参数上下文中,大多数时候它们存在的目的是为了禁用来自 Bourne 遗留问题的错误特征,而你正在显式地引起这种效果。像这样的例外情况(或者另一个例子是 case ... in),你并没有真正明确任何事情。你只是在那些本来没有作用的地方添加更多的引号。你真正想知道引号的效果在哪里,并尽可能地使这部分变得明显。这并不太重要。有经验的脚本编写者可以以任何方式处理它。 - ormaaj
谢谢!你对“有一定经验”的标准可能对我来说有点高了.. ;) - Robottinosino
@ormaaj:“这不是一种正常的理智语言。”我会把它带回家。 - onlycparra

6
不,即使它们出现在[[测试中,您也不应该总是省略引号。Bash 以省略引号而臭名昭著 :-)
在 bash 中,[[ ]] 应始终作为表达式进行评估,因此脚本将继续正常运行。风险在于逻辑错误可能会不知不觉地出现。在我能想到的所有情况下,只要加上引号就可以了。然而,引号允许您明确说明您想要什么,而且除了更安全外,还具有自说明性。
考虑以下表达式: if [[ "$INT" =~ ^-?[0-9]+$ ]]; then 即使不加引号它也可以正常工作,因为它位于 [[ ]]之间,但是添加引号可以使其更清晰,不会导致任何问题。
无论如何,这是我的看法,作为一个因未在需要时添加" "而被 Bash 搞砸的人的意见 :'(。 我的 bash 好友曾经说过:"在 Bash 中慷慨地使用引号。" 这个建议对我很有帮助。

2
明确胜于隐晦,正如受到Python启发的箴言所说。这是我一直以来的编码方式,就像我在原始帖子中所述。所以,我同意你的观点。你知道,有时候人们甚至会因为UUOC而生气,所以...不能取悦每个人。 - Robottinosino
2
对我而言,隐式比显式更好。Bash有很多上下文敏感的细节。了解确切规则非常重要。如果我看到一些潜在的冗余语法,不幸的是我必须问自己编写者在放置它时是否知道他们在做什么。因为一个复杂的脚本可能会依赖于小细节,至少在我写东西时,知道我放置某些语法是有原因的会有所帮助。最好的风格可能取决于你的经验水平。 - ormaaj
1
@ormaaj:我大部分同意,但在bash上下文中,我倾向于将事物放在双引号中作为默认选项,而任何没有被双引号包含的内容都会让我停下来思考是否有原因,以及编码人员是否知道他们在做什么... 因此,在这种情况下,本质上相同的推理使我得出相反的结论。 - Gordon Davisson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接