何时在shellvariables中引用引号?
有人可以告诉我是否应该在shell脚本中引用variables吗?
例如,以下是正确的:
xdg-open $URL [ $? -eq 2 ] 要么
 xdg-open "$URL" [ "$?" -eq "2" ] 
如果是这样,为什么?
一般规则:如果它可以是空的或者包含空格(或者任何空格),则引用它。 不用空格引用string通常会导致shell将单个参数拆分为许多。
 $? 不需要引号,因为它是一个数字值。  $URL是否需要它取决于你允许的内容,如果它是空的,你是否还想要一个参数。 
我总是习惯性地引用string,因为它更安全。
简而言之,引用您不需要shell执行令牌拆分和通配符扩展的所有内容。
单引号逐字保护它们之间的文本。 当你需要确保shell根本不接触琴弦时,它是一个合适的工具。 通常,当您不需要可变插值时,它是select的引用机制。
 $ echo 'Nothing \t in here $will change' Nothing \t in here $will change $ grep -F '@&$*!!' file /dev/null file:I can't get this @&$*!! quoting right. 
双引号适用于需要可变插值的情况。 有了适当的修改,当你在string中需要单引号时,这也是一个很好的解决方法。 (没有简单的方法来避免单引号之间的单引号,因为单引号内没有转义机制 – 如果有的话,他们不会完全逐字引用。)
 $ echo "There is no place like '$HOME'" There is no place like '/home/me' 
当您特别要求shell执行令牌拆分和/或通配符扩展时,没有引号是合适的。
令牌拆分;
  $ words="foo bar baz" $ for word in $words; do > echo "$word" > done foo bar baz 
相比之下:
  $ for word in "$words"; do echo "$word"; done foo bar baz 
(该循环只运行一次,而不是单引号string。)
  $ for word in '$words'; do echo "$word"; done $words 
(循环只运行一次,而不是单引号string。)
通配符扩展:
 $ pattern='file*.txt' $ ls $pattern file1.txt file_other.txt 
相比之下:
 $ ls "$pattern" ls: cannot access file*.txt: No such file or directory 
  (没有文件名为literally file*.txt 。) 
 $ ls '$pattern' ls: cannot access $pattern: No such file or directory 
  (没有名为$pattern文件!) 
 更具体地说,任何包含文件名的文件都应该被引用(因为文件名可以包含空格和其他shell元字符)。 任何包含URL的地方通常都会被引用(因为许多URL包含像“ ?和“ &这样的shell元字符)。 任何包含正则expression式的东西都应该引用(同上)。 除了非空白字符之间的单个空格以外,任何含有大量空格的东西都需要引用(否则,shell将把空格切入单个空格,并修剪任何前导或尾部空格)。 
 当你知道一个variables只能包含一个不包含shell元字符的值时,引用是可选的。 因此,一个没有引号的$? 基本上是好的,因为这个variables只能包含一个数字。 但是, "$?" 也是正确的,并build议一般性的一致性和正确性(虽然这是我个人的build议,不是一个广泛承认的政策)。 
 不是variables的值基本上遵循相同的规则,尽pipe您也可以转义任何元字符而不是引用它们。 对于一个常见的例子,除非元字符被转义或引用,否则带有&的URL将被shellparsing为后台命令: 
 $ wget http://example.com/q&uack [1] wget http://example.com/q -bash: uack: command not found 
(当然,如果URL是一个不带引号的variables,也会发生这种情况。)对于静态string,单引号是最有意义的,尽pipe任何forms的引用或转义都可以在这里使用。
 wget 'http://example.com/q&uack' # Single quotes preferred for a static string wget "http://example.com/q&uack" # Double quotes work here, too (no $ or ` in the value) wget http://example.com/q\&uack # Backslash escape wget http://example.com/q'&'uack # Only the metacharacter really needs quoting 
最后一个例子也提出了另一个有用的概念,我喜欢称之为“跷跷板报价”。 如果您需要混合使用单引号和双引号,则可以将它们彼此相邻。 例如,下面引用的string
 '$HOME ' "isn't" ' where `<3' "' is." 
可以粘贴在一起,形成一个单一的长串后标记和报价去除。
 $ echo '$HOME '"isn't"' where `<3'"' is." $HOME isn't where `<3' is. 
这不是很清楚,但这是一个常用的技术,因此很好知道。
 另外,脚本通常不应该使用ls 。 要扩展通配符,只需…使用它。 
 $ printf '%s\n' $pattern # not ``ls -1 $pattern'' file1.txt file_other.txt $ for file in $pattern; do # definitely, definitely not ``for file in $(ls $pattern)'' > printf 'Found file: %s\n' "$file" > done Found file: file1.txt Found file: file_other.txt 
  (在后面的例子中,循环是完全多余的; printf特别适用于多个参数stat 。但是循环遍历匹配是一个常见的问题,并且经常做错误。 
包含要循环的标记列表或通配符展开的variables不太常见,所以我们有时缩写为“引用所有内容,除非您确切知道自己在做什么”。
一般来说,这里是一个三点的引用公式:
双引号
在我们想要抑制分词和通配的情况下。 同样在我们希望文字被视为一个string,而不是正则expression式的上下文中。
单引号
在string文字中,我们要抑制插值和反斜杠的特殊处理。 换句话说,使用双引号的情况是不合适的。
没有引号
在我们绝对确信不存在分词或通配问题的情况下,或者我们希望分词和通配 。
例子
双引号
-  带空格的string( "StackOverflow rocks!","Steve's Apple")
-  variables扩展( "$var","${arr[@]}")
-  命令replace( "$(ls)",“ls”)
-  其中目录path或文件名部分包含空格( "/my dir/"*)
-  保护单引号( "single'quote'delimited'string")
-   Bash参数扩展( "${filename##*/}")
单引号
- 命令名称和参数中没有空格
-  需要插值的文本string被抑制( 'Really costs $$!','just a backslash followed by at: \t')
-  保护双引号( 'The "crux"')
- 需要插值的正则expression式文本被抑制
-  使用shell引用涉及特殊字符的文字( $'\n\t')
-  使用shell引用,我们需要保护几个单引号和双引号( $'{"table": "users", "where": "first_name"=\'Steve\'}')
没有引号
-  围绕标准数值variables( $$,$?,$#等)
-  在((count++)),"${arr[idx]}","${string:start:length}"等算术语境中。
-  里面的[[ ]]expression式是免费的分词和通配问题(这是一个风格和意见可以差异很大的问题)
-  我们想要分词的地方( for word in $words)
-  我们要在哪里for txtfile in *.txt; do ...(for txtfile in *.txt; do ...)
-  我们希望被解释为$HOME(~/"some dir"而不是"~/some dir")
也可以看看:
- Bash中单引号和双引号的区别
- 什么是特殊的美元符号shellvariables?