首先,将zsh与其余的分开。这与旧的和现代的shell无关:zsh的行为有所不同。zsh设计师决定使其与传统外壳(Bourne,ksh,bash)不兼容,但更易于使用。
其次,始终记住使用双引号要比记住何时需要双引号容易得多。大多数时候它们都是必需的,因此您将需要学习何时不需要它们,而不是何时需要它们。
简而言之,在需要单词或模式列表的任何地方都需要双引号。在解析器需要原始字符串的情况下,它们是可选的。
没有引号会发生什么
请注意,如果没有双引号,则会发生两件事。
- 首先,扩展结果(用于参数替换的变量的值,如
${foo},或用于命令替换的命令的输出,如$(foo))包含空格的任何地方都会被拆分为单词。
更准确地说,扩展结果在出现在IFS变量值(分隔符)中的每个字符处被分割。如果分隔符序列包含空格(空格,制表符或换行符),则将空格视为单个字符;否则,空格将被视为单个字符。前导,尾随或重复的非空白分隔符会导致空白字段。例如,使用IFS=" :",:one::two : three: :four 之前产生空字段one,之间one和two之间,和(单个的)three和four。 
- 如果拆分产生的每个字段包含一个字符,则将其解释为glob(通配符模式)
\[*?。如果该模式与一个或多个文件名匹配,则该模式将由匹配文件名列表替换。 
一个无引号的变量扩展$foo俗称“ split + glob运算符”,与之相反,它只"$foo"取变量值foo。命令替换"$(foo)"也是如此:是命令替换,$(foo)是后跟split + glob的命令替换。
在哪里可以省略双引号
在Bourne样式的shell中,我可以想到所有这些情况,您可以在其中编写不带双引号的变量或命令替换,并且按字面值解释值。
在作业的右侧。
var=$stuff
a_single_star=*
请注意,您确实需要在后面加上双引号export,因为它是普通的内置函数,而不是关键字。这仅在某些shell中才是正确的,例如dash,zsh(在sh仿真中),yash或posh;bash和ksh都export特别对待。
export VAR="$stuff"
 
在case声明中。
case $var in …
请注意,在案例模式中确实需要双引号。区分大小写不会在大小写模式中发生,但是将未加引号的变量解释为模式,而将带引号的变量解释为文字字符串。
a_star='a*'
case $var in
  "$a_star") echo "'$var' is the two characters a, *";;
   $a_star) echo "'$var' begins with a";;
esac
 
在双括号内。双括号是shell的特殊语法。
[[ -e $filename ]]
除了在需要模式或正则表达式的地方确实需要双引号之外:在=or ==或!=or 的右侧=~。
a_star='a*'
if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
fi
您确实需要像往常一样在单括号内加上双引号,[ … ]因为它们是普通的shell语法(这是一个恰好被称为的命令[)。请参阅单括号或双括号
 
在非交互式POSIX Shell中进行重定向(不是bash,也不是ksh88)。
echo "hello world" >$filename
一些外壳在进行交互时会将变量的值视为通配符模式。POSIX禁止在非交互式外壳中执行该操作,但是包括bash(在POSIX模式下除外)和ksh88(包括在sh某些商业Unices的POSIX(据称是Solaris)的POSIX 中发现的)在内的一些Shell仍在该外壳中进行操作(bash也尝试拆分)除非该重定向无法割裂+通配符在只有一个字的结果),这就是为什么它是最好用重定向的目标在sh脚本如果你想将它转换为bash有一天脚本,或运行的系统上,其中sh的不符合规定的在这一点上,也可来源于从交互shell。
 
在算术表达式内。实际上,您需要省略引号,以便将变量解析为算术表达式。
expr=2*2
echo "$(($expr))"
但是,您确实需要在算术扩展周围加上引号,因为在大多数外壳程序中,引号都会引起分词,因为POSIX要求使用(!?)。
 
在关联数组下标中。
typeset -A a
i='foo bar*qux'
a[foo\ bar\*qux]=hello
echo "${a[$i]}"
 
在某些罕见情况下,不带引号的变量和命令替换可能很有用:
- 当变量值或命令输出由全局模式列表组成,并且您要将这些模式扩展到匹配文件列表时。
 
- 当您知道该值不包含任何通配符时,则该值
$IFS未被修改,并且您希望将其拆分为空白字符。 
- 当您想在某个字符处分割值时:使用禁用globlob 
set -f,将其设置IFS为分隔符(或将其保留以在空白处分割),然后进行扩展。 
sh
在zsh中,除了少数例外,大多数情况下可以省略双引号。
$var从不扩展为多个单词,但是如果的值为var空字符串,则它将扩展为空列表(与包含单个空单词的列表相对)。对比:
var=
print -l $var foo        # prints just foo
print -l "$var" foo      # prints an empty line, then foo
同样,"${array[@]}"扩展为数组的所有元素,而$array仅扩展为非空元素。
 
该@参数扩展标志有时需要围绕整个替换双引号:"${(@)foo}"。
 
如果不加引号,则命令替换将进行字段拆分:echo $(echo 'a'; echo '*')打印a *(用单个空格),而echo "$(echo 'a'; echo '*')"打印未修改的两行字符串。使用"$(somecommand)"得到命令的输出就是一个字,SANS最终换行符。使用"${$(somecommand; echo _)%?}"获得包括最后的换行命令的确切输出。用于"${(@f)$(somecommand)}"从命令的输出获取行的数组。
 
               
              
SH_WORD_SPLIT选项影响。