这两个 Bash if 语句有什么区别?例如
if [ "$FOO" = "true" ]; then
对比
if [ $FOO = "true" ]; then
有什么区别? 看起来这两个语句的作用是一样的。
答案1
如果 的值$FOO
是不包含通配符 的单个单词\[*?
,则两者相同。
如果$FOO
未分配,或为空,或多于一个单词(即包含空格或$IFS
),则未加引号的版本是语法错误。如果它恰好是正确的单词序列(例如0 -eq 0 -o false
),则结果可能是任意的。因此,最好在 shell 脚本中始终引用变量。
顺便说一下,"true"
不需要引用。
答案2
为了说明它可能导致什么问题,这里举几个例子。
假设我们有两个变量,如下所示:
FOO="some value"
BAR="some value"
现在我们有两个变量保存完全相同的字符串/值。如果我们做了一些 if 语句来测试结果,在您的情况下:
if [ $FOO = "$BAR" ]; then echo "match"; else echo "no match"; fi
此时你会得到bash: [: too many arguments
.不带引号的 $FOO 现在包含三个值,即'[ , some , value'
. [
test 关键字不知道要执行什么,因为它期望第一个或第二个参数是运算符。
当我们引用“$FOO”时,我们明确告诉if
我们要查看没有发生分词的正确值。
另一个例子:
my_file="A random file.txt"
- 这样做
rm $my_file
意味着删除“A”“随机”“file.txt”,使其成为三个文件。 - 这样做
rm "$my_file"
将删除“A random file.txt”,该文件生成一个文件。
希望我没有让你对这些例子感到困惑。
答案3
在这里,重要的不是在if
语句中引用,而是在任何命令的参数中,在特定情况下,是命令[
。
该[
命令与任何其他命令一样(尽管它内置在大多数类似 Bourne 的 shell 中),并且与任何其他命令一样可以在语句的if
, then
, elif
,else
部分if...fi
以及外部if...fi
语句中使用。
在除 之外的类似 Bourne 的 shell 中zsh
,将参数扩展不加引号是分割+全局操作员。
$FOO
,将根据使用复杂规则的字符进行分割$IFS
,并且生成的单词受文件名生成的影响,这将在命令中生成可变数量的参数,[
而它期望的参数恰好是一个。
因此,就像任何命令的任何参数一样,$FOO
必须用引号引起来,以便其内容作为一个参数传递。
[
是其中的命令之一批判的不要忘记引用变量,因为不这样做相当于在许多[
实现中进行任意命令注入(如果变量的内容有可能最终受到攻击者的控制)。
这包括、、和衍生工具(以及在/仿真中时)[
的内置实用程序,以及 Solaris 等系统的独立实用程序(、...),在这些系统中,它作为内置的包装脚本实现。bash
ksh88
ksh93
pdksh
zsh
sh
ksh
[
/bin/[
/usr/xpg4/bin/[
ksh
[
这些[
实现(例如 shell 中的所有内置命令)在某些情况下可以解释算术表达式或可以对变量名称进行操作,最终可以执行代码。
这里作为一个例子,在bash
shell(GNU 项目的 shell,也是sh
一些系统的实现)中,默认值为$IFS
:
bash-5.0$ FOO='-v x[$(reboot)] -o true'
bash-5.0$ if [ $FOO = "true" ]; then echo yes; fi
System rebooting now!
yes
因为它没有被引用,并且$IFS
默认包含 SPC 字符,所以$FOO
被拆分为-v
, x[$(reboot)]
,-o
和true
。其中,只有第二个包含全局运算符 ( [...]
)。就我而言,它与任何文件都不匹配(例如,如果当前目录中有一个xo
文件,情况会有所不同),因此保持原样(Bourne-like shell 的另一个特点,大多数其他 shell 会抱怨全局不匹配)。
因此,最终会询问数组[
是否$x
设置为 indice $(reboot)
,并最终reboot
作为该算术表达式求值的一部分运行,或者 ( -o
) 是否true
等于true
,因此是yes
输出。
更多阅读:
答案4
在这个具体情况下没有区别。
但是,如果$FOO
包含空格或一些特殊字符,就会遇到问题。
在这种"$FOO"
情况下,它将使用总计变量,以使匹配使您免受空间问题的影响。
但是,如果使用$FOO
and有特殊情况的话就会影响if语句。