shell 我应该在环境路径名中使用引号吗?

sgtfey8w  于 2022-11-16  发布在  Shell
关注(0)|答案(4)|浏览(114)

我正在清理我所有的配置文件,试图使它们尽可能的可读。我一直在寻找一个关于在导出路径时使用引号的风格指南,例如,一个~/.bashrc文件:

export PATH="/users/me/path:$PATH"

对比

export PATH=/users/me/path:$PATH

Google shell风格指南建议避免在路径名中使用引号。相比之下,很多流行的点文件存储库(如Zach Holman的here)都使用引号。在路径中使用引号有什么好处吗?

p4rjhz4m

p4rjhz4m1#

向@gniourf_gniourf和@chepner致敬,感谢他们的帮助。

tl;dr
为安全起见,请使用双引号:它可以在所有情况下工作,可以跨所有类似POSIX的shell。

如果要添加一个基于~的路径,* 选择性地 * 保留~/ * 不加引号 * 以确保~被扩展;例如:export PATH=~/"bin:$PATH"。请参阅以下有关变量赋值中~扩展的规则。
或者,只需在单个双引号字符串中使用$HOME
export PATH="$HOME/bin:$PATH"
注意:以下内容适用于**bashkshzsh**,但不适用于(大多数情况下)严格符合POSIX的shell,如dash;因此,当您以/bin/sh为目标时,您必须将export的RHS用双引号引起来。[1]

  • 双引号是**可选的 ,仅当RHS的 literal 部分(要分配的值)既不包含空格也不包含其他shell元字符时。
    • 所引用 * 变量的值是否包含空格/元字符 * 无关 *-请参见下文。
  • 再次强调:当使用export时,它 * 确实 * 与sh有关,所以总是在那里使用双引号。

在这种情况下,您可以不使用双引号,原因是类POSIX shell中的variable-assignment 语句对它们的RHS * 的解释 * 与传递给 * 命令*的 * 参数 * 不同,如POSIX规范的第2.9.1节所述:

  • 具体来说,即使 * 执行了 * 初始 * 分词 *,它也只适用于 * 未扩展 *(原始)RHS(这就是为什么您 * 确实 * 需要在 * 文字 * 中使用空格/元字符引用),而不适用于它的 * 结果 *。
  • 这**仅适用于以下形式的 * 真正 * 赋值语句

<name>=<value>在 * 所有 * 类POSIX shell **中,即,如果在变量名之前 * 没有命令名 *;注意,这包括对命令的赋值 * 前置 *,以为其定义特定环境变量,例如X1 M16 N1 X。

*其他命令 * 上下文中的赋值 * 应始终用双引号引起来,以确保安全:

  • 对于sh(在(大多数)严格遵循POSIX的shell中,如dash),带有export的赋值被视为 * 常规命令 *,而foo=$bar部分被视为export内置的 * 第一个参数 *,因此被视为正常(也受 result 的分词限制)。

(POSIX没有指定任何其他涉及(显式)变量赋值的命令; declaretypesetlocal是非标准 * 扩展 *)。

  • bashkshzsh,与POSIX有一个可以理解的偏差,将赋值逻辑扩展到export foo=$bartypeset/declare/local foo=$bar。换句话说:*bashkshzshexport/typeset/declare/local中,命令被视为 * 赋值 ,因此不一定需要加引号
  • 也许令人惊讶的是,同样选择实现 non-POSIX local builtin[2]的dash并没有向其扩展赋值逻辑;然而,这与其export行为一致。
  • 传递给env的赋值语句(例如env foo=$bar cmd ...)也会作为命令参数进行扩展,因此需要双引号-zsh除外。
  • 在这方面,envkshbash中的export的行为不同,这是因为env是一个 * 外部实用程序 *,而export是一个 *shell内置 *。

(当涉及到未引用的变量引用时,zsh的行为 * 从根本上 * 与其他shell不同)。

*颚化符(~)扩展在 * 真正 * 赋值语句中发生如下:

  • 除了~需要像往常一样被 unquoted 之外,它还仅适用于:
  • 如果 * 整个 * RHS是~;例如:
  • x1米50英寸
  • 否则:* 仅 * 当 * 同时 * 满足以下条件时:
  • 如果字符串以~开头或前面有 unquoted:
  • 如果~后面跟着 * 不带引号的 * /,则为。
  • 例如,可以是,

x1米55英寸1x
foo=$foo:~/bin # same as foo="$foo:$HOME/bin"

示例

此示例说明在bashkshzsh中,即使使用export,也可以 * 不 * 使用双引号,但 * 我不建议 * 使用双引号。

#!/usr/bin/env bash
# or ksh or zsh - but NOT /bin/sh!

# Create env. variable with whitespace and other shell metacharacters
export FOO="b:c &|<> d"

# Extend the value - the double quotes here are optional, but ONLY 
# because the literal part, 'a:`, contains no whitespace or other shell metacharacters.
# To be safe, DO double-quote the RHS.
export FOO=a:$foo # OK - $FOO now contains 'a:b:c &|<> d'

[1]正如@gniourf_gniourf所指出的:使用export来 * 修改 * PATH的值是可选的,因为一旦变量被标记为导出,就可以使用常规赋值(PATH=...)来更改其值。
也就是说,您仍然可以 * 选择 * 使用export,以便明确地导出正在修改的变量。
[2]@gniourf_gniourf声明POSIX标准的未来版本可能会引入local内置。

rbpvctlc

rbpvctlc2#

当我在docker .env文件中设置环境路径名时,我使用了上面的这些答案,并得到了一些信息。我把这些信息放在这里,供其他寻找如何为docker定义环境变量的人参考。
Docker compose从.env文件中读取环境变量,该文件位于运行Docker compose的同一文件夹中,如下所述https://docs.docker.com/compose/env-file.
但是,docker compose需要定义不带引号的环境变量,而不是用引号将值括起来,除非引号是值的一部分。
引号没有特殊处理(即,它们将是瓦尔的一部分,您已收到警告;)
我试图设置绝对路径的NODE_PATH=./src,以便在docker部署的react应用程序中工作,但我把它写成了NODE_PATH="./src"

b4qexyjb

b4qexyjb3#

test 123是UNIX上的有效路径名。请尝试

PATH=test 123

它将返回:

123: command not found

甚至

export PATH=test 123

它将返回

bash export: `123': not a valid identifier

它回答了你的问题吗?
老实说,我不会遵循这样的第四方 * 风格指南 *。虽然我很惊讶,甚至谷歌广告这样错误的建议。
我会跟着:

(to小心延长)

ezykj2lf

ezykj2lf4#

与路径无关,但与https://stackoverflow.com/a/48411223相同,我在docker compose的上下文中也得到了位。
我的.env文件中有一个标记env变量,类似于

MY_TOKEN="abc$123"

并且得到了无效登录凭据错误,因为容器中的MY_TOKEN值是abc&123。实际的令牌要长得多,所以很难发现问题。

MY_TOKEN='abc$123'

成功了。

相关问题