例如,下面的写法是否正确:
xdg-open $URL
[ $? -eq 2 ]
或者
xdg-open "$URL"
[ "$?" -eq "2" ]
如果是这样的话,为什么呢?
xdg-open $URL
[ $? -eq 2 ]
或者
xdg-open "$URL"
[ "$?" -eq "2" ]
一般规则:如果字符串可以为空或包含空格(或者任意空白字符)或特殊字符(通配符),则需要加引号。如果不使用带有空格的字符串,则会导致shell将单个参数分解为多个。
$?
不需要引号,因为它是一个数字值。是否需要在 $URL
中加引号取决于您允许在其中输入什么以及是否仍希望在其为空时保留参数
出于习惯,我倾向于始终添加引号,因为这样更安全。
IFS=0
,那么echo $?
可能会非常惊人。 - Charles Duffycp $source1 $source2 $dest
,但如果由于某些意外原因未设置dest
,第三个参数就会消失,并且它将悄悄地将source1
复制到source2
上,而不是为空目标提供适当的错误(如果您引用了每个参数,则会出现这种情况)。 - Derek Veit$ 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.
当需要变量插值时,双引号是合适的。通过适当的调整,它也是在字符串中需要单引号时的一个很好的解决方法。(在单引号之间转义单引号没有直接的方法,因为单引号内部没有转义机制——如果有的话,它们将不完全引用原样。)
$ echo "There is no place like '$HOME'"
There is no place like '/home/me'
$ 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
$ for word in '$words'; do echo "$word"; done
$words
$ pattern='file*.txt'
$ ls $pattern
file1.txt file_other.txt
$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory
(没有名为file*.txt
的文件。)
$ ls '$pattern'
ls: cannot access $pattern: No such file or directory
(没有名为$pattern
的文件!)
更具体地说,任何包含文件名的内容通常应该加引号(因为文件名可能包含空格和其他shell元字符)。任何包含URL的内容通常应该加引号(因为许多URL包含像?
和&
这样的shell元字符)。任何包含正则表达式的内容通常应该加引号(同上)。任何包含除非单个空格之外的显着空格的内容都需要加引号(否则,shell将把空格混合成实际上是单个空格,并修剪任何前导或尾随空格)。
当您知道变量只能包含不含shell元字符的值时,引用是可选的。因此,未引用的$?
基本上是可以的,因为此变量只能包含单个数字。但是,"$?"
也是正确的,并且出于一般一致性和正确性的考虑建议使用(尽管这是我的个人建议,而不是广泛认可的政策)。
非变量的值基本上遵循相同的规则,但您也可以转义任何元字符而不是引用它们。例如,一个带有&
的URL将被shell解析为后台命令,除非转义或引用元字符:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
当然,如果URL在未使用引号的变量中,则也会发生这种情况。对于静态字符串,单引号是最合适的选择,尽管任何形式的引用或转义都可以在此处使用。
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
'$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
也是如此。但是循环通配符匹配是一个常见的问题,经常被错误地执行。NULL="$(php -r 'echo chr(0);')"
+ printf "%s" "$NULL" | wc -c
将会打印 0... - hanshenrik$$
, $?
, $#
等)((count++))
, "${arr[idx]}"
, "${string:start:length}"
[[ ]]
表达式中,它不会被分割和扩展 (这是一种风格问题,意见可能存在很大差异)for word in $words
)for txtfile in *.txt; do ...
)~
为 $HOME
的地方 (~/"some dir"
但不包括 "~/some dir"
)另请参阅:
"ls" "/"
。需要更加仔细地限定“所有字符串上下文”的意思。 - William Pursell[[ ]]
中,引号在=
/==
和=~
的右侧是有影响的:它决定了是将字符串作为模式/正则表达式解释还是按字面意思解释。 - Benjamin W.$'...'
)应该有自己的章节。 - mklement0"ls" "/"
而不是更常见的ls /
,我认为这是准则中的一个严重缺陷。 - William Pursellcase
:) - PesaThe通常我会使用带引号的形式,例如"$var"
以确保安全,除非我确定$var
不包含空格。
我也会使用$var
作为连接行的简单方式:
lines="`cat multi-lines-text-file.txt`"
echo "$lines" ## multiple lines
echo $lines ## all spaces (including newlines) are zapped
*
,那么_bash_将用当前目录中所有文件的列表替换它。哈哈。不是笑话。 - bobbogo