Linux 什么时候用引号将 shell 变量括起来?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10067266/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:40:45  来源:igfitidea点击:

When to wrap quotes around a shell variable?

linuxbashshellunixquotes

提问by Cristian

Could someone tell me whether or not I should wrap quotes around variables in a shell script?

有人能告诉我是否应该在 shell 脚本中用引号将变量括起来吗?

For example, is the following correct:

例如,以下是否正确:

xdg-open $URL 
[ $? -eq 2 ]

or

或者

xdg-open "$URL"
[ "$?" -eq "2" ]

And if so, why?

如果是这样,为什么?

采纳答案by paxdiablo

General rule: quote it if it can either be empty or contain spaces (or any whitespace really) or special characters (wildcards). Not quoting strings with spaces often leads to the shell breaking apart a single argument into many.

一般规则:如果它可以为空或包含空格(或任何空格)或特殊字符(通配符),则引用它。不引用带空格的字符串通常会导致 shell 将单个参数分解为多个参数。

$?doesn't need quotes since it's a numeric value. Whether $URLneeds it depends on what you allow in there and whether you still want an argument if it's empty.

$?不需要引号,因为它是一个数值。是否$URL需要它取决于你在那里允许的内容以及如果它是空的你是否仍然想要一个参数。

I tend to always quote strings just out of habit since it's safer that way.

我倾向于总是出于习惯引用字符串,因为这样更安全。

回答by tripleee

In short, quote everything where you do not require the shell to perform token splitting and wildcard expansion.

简而言之,引用不需要 shell 执行标记拆分和通配符扩展的所有内容。

Single quotes protect the text between them verbatim. It is the proper tool when you need to ensure that the shell does not touch the string at all. Typically, it is the quoting mechanism of choice when you do not require variable interpolation.

单引号逐字保护它们之间的文本。当您需要确保外壳根本不接触琴弦时,它是合适的工具。通常,当您不需要变量插值时,它是首选的引用机制。

$ 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.

Double quotes are suitable when variable interpolation is required. With suitable adaptations, it is also a good workaround when you need single quotes in the string. (There is no straightforward way to escape a single quote between single quotes, because there is no escape mechanism inside single quotes -- if there was, they would not quote completely verbatim.)

当需要变量插值时,双引号是合适的。通过适当的改编,当您需要在字符串中使用单引号时,这也是一个很好的解决方法。(没有直接的方法可以在单引号之间转义单引号,因为单引号内没有转义机制——如果有,它们就不会完全逐字引用。)

$ echo "There is no place like '$HOME'"
There is no place like '/home/me'

No quotes are suitable when you specifically require the shell to perform token splitting and/or wildcard expansion.

当您特别要求 shell 执行标记拆分和/或通配符扩展时,没有引号是合适的。

Token splitting;

代币分裂;

 $ words="foo bar baz"
 $ for word in $words; do
 >   echo "$word"
 > done
 foo
 bar
 baz

By contrast:

相比之下:

 $ for word in "$words"; do echo "$word"; done
 foo bar baz

(The loop only runs once, over the single, quoted string.)

(循环仅在单个带引号的字符串上运行一次。)

 $ for word in '$words'; do echo "$word"; done
 $words

(The loop only runs once, over the literal single-quoted string.)

(循环只在文字单引号字符串上运行一次。)

Wildcard expansion:

通配符扩展:

$ pattern='file*.txt'
$ ls $pattern
file1.txt      file_other.txt

By contrast:

相比之下:

$ ls "$pattern"
ls: cannot access file*.txt: No such file or directory

(There is no file named literally file*.txt.)

(没有按字面命名的文件file*.txt。)

$ ls '$pattern'
ls: cannot access $pattern: No such file or directory

(There is no file named $pattern, either!)

(也没有名为 的文件$pattern!)

In more concrete terms, anything containing a filename should usually be quoted (because filenames can contain whitespace and other shell metacharacters). Anything containing a URL should usually be quoted (because many URLs contain shell metacharacters like ?and &). Anything containing a regex should usually be quoted (ditto ditto). Anything containing significant whitespace other than single spaces between non-whitespace characters needs to be quoted (because otherwise, the shell will munge the whitespace into, effectively, single spaces, and trim any leading or trailing whitespace).

更具体地说,通常应该引用任何包含文件名的内容(因为文件名可以包含空格和其他 shell 元字符)。任何包含 URL 的内容通常都应该被引用(因为许多 URL 包含像?和这样的 shell 元字符&)。通常应该引用任何包含正则表达式的内容(同上)。任何包含非空白字符之间除单个空格以外的重要空格的内容都需要引用(否则,shell 会将空格有效地转换为单个空格,并修剪任何前导或尾随空格)。

When you know that a variable can only contain a value which contains no shell metacharacters, quoting is optional. Thus, an unquoted $?is basically fine, because this variable can only ever contain a single number. However, "$?"is also correct, and recommended for general consistency and correctness (though this is my personal recommendation, not a widely recognized policy).

当您知道一个变量只能包含一个不包含 shell 元字符的值时,引号是可选的。因此,不带引号$?的基本上没问题,因为这个变量只能包含一个数字。然而,"$?"它也是正确的,并推荐用于一般的一致性和正确性(尽管这是我个人的建议,而不是广泛认可的政策)。

Values which are not variables basically follow the same rules, though you could then also escape any metacharacters instead of quoting them. For a common example, a URL with a &in it will be parsed by the shell as a background command unless the metacharacter is escaped or quoted:

不是变量的值基本上遵循相同的规则,尽管您也可以转义任何元字符而不是引用它们。对于一个常见的例子,&除非元字符被转义或引用,否则带有 a 的 URL将被 shell 解析为后台命令:

$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found

(Of course, this also happens if the URL is in an unquoted variable.) For a static string, single quotes make the most sense, although any form of quoting or escaping works here.

(当然,如果 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

The last example also suggests another useful concept, which I like to call "seesaw quoting". If you need to mix single and double quotes, you can use them adjacent to each other. For example, the following quoted strings

最后一个例子还提出了另一个有用的概念,我喜欢称之为“跷跷板引用”。如果需要混合使用单引号和双引号,可以将它们相邻使用。例如,以下带引号的字符串

'$HOME '
"isn't"
' where `<3'
"' is."

can be pasted together back to back, forming a single long string after tokenization and quote removal.

可以背靠背粘贴在一起,在标记化和引号删除后形成一个长字符串。

$?echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.

This isn't awfully legible, but it's a common technique and thus good to know.

这不是非常清晰,但它是一种常见的技术,因此很高兴知道。

As an aside, scripts should usually not use lsfor anything.To expand a wildcard, just ... use it.

顺便说一句,脚本通常不应该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

(The loop is completely superfluous in the latter example; printfspecifically works fine with multiple arguments. stattoo. But looping over a wildcard match is a common problem, and frequently done incorrectly.)

(在后一个示例中,循环完全是多余的;printf特别是对于多个参数stat也可以正常工作。但循环通配符匹配是一个常见问题,并且经常不正确。)

A variable containing a list of tokens to loop over or a wildcard to expand is less frequently seen, so we sometimes abbreviate to "quote everything unless you know precisely what you are doing".

包含要循环的标记列表或要扩展的通配符的变量不太常见,因此我们有时缩写为“引用所有内容,除非您确切地知道自己在做什么”。

回答by codeforester

Here is a three-point formula for quotes in general:

以下是一般报价的三点公式:

Double quotes

双引号

In contexts where we want to suppress word splitting and globbing. Also in contexts where we want the literal to be treated as a string, not a regex.

在我们想要抑制分词和通配的上下文中。同样在我们希望将文字视为字符串而不是正则表达式的上下文中。

Single quotes

单引号

In string literals where we want to suppress interpolation and special treatment of backslashes. In other words, situations where using double quotes would be inappropriate.

在我们想要抑制插值和反斜杠特殊处理的字符串文字中。换句话说,使用双引号的情况是不合适的。

No quotes

没有引号

In contexts where we are absolutely sure that there are no word splitting or globbing issues or we do want word splitting and globbing.

在我们绝对确定没有分词或通配问题的情况下,或者我们确实想要分词和通配



Examples

例子

Double quotes

双引号

  • literal strings with whitespace ("StackOverflow rocks!", "Steve's Apple")
  • variable expansions ("$var", "${arr[@]}")
  • command substitutions ("$(ls)", "`ls`")
  • globs where directory path or file name part includes spaces ("/my dir/"*)
  • to protect single quotes ("single'quote'delimited'string")
  • Bash parameter expansion ("${filename##*/}")
  • 带有空格 ( "StackOverflow rocks!", "Steve's Apple") 的文字字符串
  • 变量扩展 ( "$var", "${arr[@]}")
  • 命令替换 ( "$(ls)", "`ls`")
  • globs 目录路径或文件名部分包含空格 ( "/my dir/"*)
  • 保护单引号 ( "single'quote'delimited'string")
  • Bash 参数扩展 ( "${filename##*/}")

Single quotes

单引号

  • command names and arguments that have whitespace in them
  • literal strings that need interpolation to be suppressed ( 'Really costs $$!', 'just a backslash followed by a t: \t')
  • to protect double quotes ('The "crux"')
  • regex literals that need interpolation to be suppressed
  • use shell quoting for literals involving special characters ($'\n\t')
  • use shell quoting where we need to protect several single and double quotes ($'{"table": "users", "where": "first_name"=\'Steve\'}')
  • 包含空格的命令名称和参数
  • 需要抑制插值的文字字符串 ( 'Really costs $$!', 'just a backslash followed by a t: \t')
  • 保护双引号 ( 'The "crux"')
  • 需要抑制插值的正则表达式文字
  • 对涉及特殊字符 ( $'\n\t') 的文字使用 shell 引用
  • 在需要保护多个单引号和双引号 ( $'{"table": "users", "where": "first_name"=\'Steve\'}') 的地方使用 shell 引用

No quotes

没有引号

  • around standard numeric variables ($$, $?, $#etc.)
  • in arithmetic contexts like ((count++)), "${arr[idx]}", "${string:start:length}"
  • inside [[ ]]expression which is free from word splitting and globbing issues (this is a matter of style and opinions can vary widely)
  • where we want word splitting (for word in $words)
  • where we want globbing (for txtfile in *.txt; do ...)
  • where we want ~to be interpreted as $HOME(~/"some dir"but not "~/some dir")
  • 围绕标准数值变量($$$?$#等)
  • 在算术上下文中,例如((count++)), "${arr[idx]}","${string:start:length}"
  • [[ ]]没有分词和通配符问题的内部表达(这是一个风格问题,意见可能会有很大差异)
  • 我们想要分词的地方 ( for word in $words)
  • 我们想要通配 ( for txtfile in *.txt; do ...)
  • 我们想~被解释为$HOME(~/"some dir"但不是"~/some dir")


See also:

也可以看看:

回答by Bach Lien

I generally use quoted like "$var"for safe, unless I am sure that $vardoes not contain space.

"$var"为了安全起见,我通常使用引号 like ,除非我确定它$var不包含空格。

I do use $varas a simple way to join lines:

我确实使用$var一种简单的方式来连接线:

lines="`cat multi-lines-text-file.txt`"
echo "$lines"                             ## multiple lines
echo $lines                               ## all spaces (including newlines) are zapped

回答by Vipul Sharma

For using the variables in the shell script use " " quoted variables as the quoted one means that the variable may contain spaces or special character which won't affect the execution of your shell script. Else if you are sure of not having any spaces or special character in your variable name then you may use them without " ".

要在 shell 脚本中使用变量,请使用 " " 带引号的变量作为带引号的变量,这意味着该变量可能包含不会影响 shell 脚本执行的空格或特殊字符。否则,如果您确定变量名中没有任何空格或特殊字符,那么您可以在没有“”的情况下使用它们。

Example:

例子:

echo "$url name" -- ( Can be used at all times )

echo "$url name" --(可以一直使用)

echo "$url name" -- ( Cannot be used at such situations so take precaution before using it )

echo "$url name" -- (在这种情况下不能使用,所以使用前要小心)