bash 中带双引号与不带双引号有什么区别

bash 中带双引号与不带双引号有什么区别

我有一些 bash 脚本,其中一个包含以下内容:

#!/bin/bash
source $(dirname ${BASH_SOURCE[0]})/script.sh

而另一则内容如下:

#!/bin/bash
source "$(dirname ${BASH_SOURCE[0]})/script.sh"

这些脚本的行为有何不同以及为什么?什么区别?

答案1

不带引号的字符串受分词通配。也可以看看Bash 陷阱#14

比较

$ echo $(printf 'foo\nbar\nquux\n*')
foo bar quux ssh-13yzvBMwVYgn ssh-3JIxkphQ07Ei ssh-6YC5dbnk1wOc 

$ echo "$(printf 'foo\nbar\nquux\n*')"
foo
bar
quux
*

当发生分词时,第一个字符IFS充当分隔符(默认情况下是空格)。

几乎在所有情况下您都需要添加引号。有一些例外,例如

  • 在不发生分词/通配的表达式中,例如简单(非数组)赋值和语句case。以下都是安全的:

    • foo=*
    • foo=${bar}qux${quux}
    • foo=$(bar "${quux}")
    • case ${var} in

    然而,这不是(如果您所追求的是带有字面星号字符的单个元素):

    • foo=( * )
  • 当您特别希望进行分词时,例如循环遍历以空格分隔的字符串中的标记(禁用通配符)。但是 - 如果可能,请使用数组。

答案2

主要区别在于引用的版本不受 shell 的字段分割的影响。

使用双引号,命令扩展的结果将作为source命令的一个参数提供。如果没有引号,它将被分解为多个参数,具体取决于IFS默认情况下包含空格、TAB 和换行符的值。

如果目录名称不包含此类空格,则不会发生字段拆分。

根据经验,最好在命令替换和变量扩展中使用双引号。

答案3

最重要的区别可能是脚本所在的目录中是否有空格。在这种情况下,第一行(没有双引号的行)将会失败。这将是 bash 对不带引号的字符串进行“分词”的结果。

假设 的结果dirname ${BASH_SOURCE[0]}/home/j r/bin。考虑不带引号的行:

source $(dirname ${BASH_SOURCE[0]})/script.sh

在这种情况下,bash 将看到以下命令:

source /home/j r/bin/script.sh

分词后,该source命令会看到脚本名称/home/j和脚本参数r/bin/script.sh。很可能没有该名称的脚本,bash 将返回错误消息:

bash: /bin/j: No such file or directory

现在考虑一下双引号会发生什么:

source "$(dirname ${BASH_SOURCE[0]})/script.sh"

在这种情况下,source 命令将查找名为的脚本/home/j r/bin/script.sh并尝试获取它。

为了完整起见,让我们考虑单引号:

source '$(dirname ${BASH_SOURCE[0]})/script.sh'

在这种情况下,与前两种不同的是,dirname它永远不会被执行。 source 命令将尝试使用文字 name 来获取命令$(dirname ${BASH_SOURCE[0]})/script.sh。可能不存在这样的文件,bash 将发出错误消息。

bash 如何处理双引号中的字符串在以下内容中有详细描述man bash

  Enclosing characters in double quotes preserves the  literal  value  of
   all  characters  within the quotes, with the exception of $, `, \, and,
   when history expansion is enabled, !.  The characters $  and  `  retain
   their  special meaning within double quotes.  The backslash retains its
   special meaning only when followed by one of the following  characters:
   $,  `,  ", \, or <newline>.  A double quote may be quoted within double
   quotes by preceding it with a backslash.  If enabled, history expansion
   will  be  performed  unless an !  appearing in double quotes is escaped
   using a backslash.  The backslash preceding the !  is not removed.

相关内容