什么时候用引号括住shell变量?

xwmevbvl  于 2022-11-16  发布在  Shell
关注(0)|答案(5)|浏览(149)

我应该还是不应该在shell脚本中的变量周围加上引号?
例如,下列是否正确:

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

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

如果是,为什么?

c7rzv4ha

c7rzv4ha1#

一般规则:如果它可以是空的或包含空格(或任何空格)或特殊字符(通配符),则用引号将其括起来。不使用空格将字符串括起来通常会导致shell将一个参数拆分为多个参数。
$?不需要引号,因为它是一个数值。$URL是否需要引号取决于您在其中允许的内容,以及如果它为空,您是否仍然需要参数。
出于习惯,我倾向于引用字符串,因为这样更安全。

8ftvxx2r

8ftvxx2r2#

简 而言 之 , 引用 不 需要 shell 执行 单词 拆分 和 通配符 扩展 的 所有 内容 。
单 引号 保护 它们 之间 的 文本 。 当 你 需要 确保 shell 完全 不 接触 字符 串 时 , 它 是 合适 的 工具 。 通常 , 当 你 不 需要 变量 插值 时 , 它 是 引用 机制 的 选择 。

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

格式
当 您 特别 要求 shell 执行 单词 拆分 和/或 通配符 扩展 时 , 不 适合 使用 引号 。
Word splitting ( 也 称为 令牌 分割 ) ;

$ 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

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

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

格式
(The循环 只 在 单 引号 字符 串 上 运行 一 次 。 )
通配符 扩展 :

$ 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

格式
(Of当然 , 如果 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.

格式
这 不是 很 清楚 , 但 这 是 一 个 常见 的 技术 , 因此 很 好 地 了解 。
顺便 说 一 句 , 脚本 should usually not use ls for anything. 要 扩展 通配符 , 只需 ... 使用 它 。

$ 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循环 在 后 一 个 示例 中 是 完全 多余 的 ; printf 特别 适用 于 多 个 参数 , stat 也 是 如此 。 但是 在 通配符 匹配 上 循环 是 一 个 常见 的 问题 , 而且 经常 会 出现 错误 。 )
一 个 变量 包含 一 系列 要 循环 使用 的 标记 或 一 个 要 扩展 的 通配符 , 这种 情况 不 太 常见 , 所以 我们 有时 会 缩写 为 " 引用 所有 内容 , 除非 你 确切 地 知道 你 在 做 什么 " 。

7nbnzgx9

7nbnzgx93#

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

双引号

在我们希望禁止单词拆分和匹配的上下文中,也在我们希望将文字作为字符串而不是正则表达式处理的上下文中。

单引号

在字符串文字中,我们希望禁止插入和反斜杠的特殊处理。换句话说,使用双引号是不合适的。

无引号

在上下文中,我们绝对确定没有单词拆分或匹配问题,或者我们 * 确实希望单词拆分和匹配 *。

示例
双引号

  • 带有空格的文字字符串("StackOverflow rocks!""Steve's Apple"
  • 变量展开("$var""${arr[@]}"
  • 命令替换("$(ls)""ls"
  • 目录路径或文件名部分包含空格的globs("/my dir/"*
  • 保护单引号("single'quote'delimited'string"
  • Bash参数扩展("${filename##*/}"
    单引号
  • 包含空格的命令名和参数
  • 需要隐藏插值的文字字符串('Really costs $$!''just a backslash followed by a t: \t'
  • 保护双引号('The "crux"'
  • 需要取消插值的正则表达式文字
  • 对包含特殊字符的文字使用shell引号($'\n\t'
  • 在需要保护多个单引号和双引号($'{"table": "users", "where": "first_name"=\'Steve\'}')的地方使用shell引号
    无引号
  • 标准数值变量($$$?$#等)周围
  • ((count++))"${arr[idx]}""${string:start:length}"等算术上下文中
  • [[ ]]表达式中,没有单词拆分和globbing问题(这是一个风格问题,意见可能会有很大差异)
  • 在这里我们需要单词拆分(for word in $words
  • 需要全局匹配的位置(for txtfile in *.txt; do ...
  • 其中,我们希望将~解释为$HOME~/"some dir"但不是"~/some dir"

另请参阅:

ymzxtsji

ymzxtsji4#

我通常使用引号,如"$var",以确保安全,除非我确定$var不包含空格。
我使用$var作为连接行的简单方法:

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

06odsfpq5#

每当编辑器的https://www.shellcheck.net/插件要求您这样做时。

相关问题