shell脚本“if”语句中引用变量之间的区别?

shell脚本“if”语句中引用变量之间的区别?

这两个 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 等系统的独立实用程序(、...),在这些系统中,它作为内置的包装脚本实现。bashksh88ksh93pdkshzshshksh[/bin/[/usr/xpg4/bin/[ksh[

这些[实现(例如 shell 中的所有内置命令)在某些情况下可以解释算术表达式或可以对变量名称进行操作,最终可以执行代码。

这里作为一个例子,在bashshell(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)],-otrue。其中,只有第二个包含全局运算符 ( [...])。就我而言,它与任何文件都不匹配(例如,如果当前目录中有一个xo文件,情况会有所不同),因此保持原样(Bourne-like shell 的另一个特点,大多数其他 shell 会抱怨全局不匹配)。

因此,最终会询问数组[是否$x设置为 indice $(reboot),并最终reboot作为该算术表达式求值的一部分运行,或者 ( -o) 是否true等于true,因此是yes输出。

更多阅读:

答案4

在这个具体情况下没有区别。

但是,如果$FOO包含空格或一些特殊字符,就会遇到问题。

在这种"$FOO"情况下,它将使用总计变量,以使匹配使您免受空间问题的影响。

但是,如果使用$FOOand有特殊情况的话就会影响if语句。

相关内容