【问题标题】:Why do quotes in shell scripts behave differently from quotes in shell commands?为什么 shell 脚本中的引号与 shell 命令中的引号不同?
【发布时间】:2019-01-13 18:19:48
【问题描述】:

我在 Windows 10 和 bash 上使用 WSL (Ubuntu 18.04)。

我有一个文件filename.gpg,内容如下:

export SOME_ENV_VAR='123'

现在我运行以下命令:

$ $(gpg -d filename.gpg)
$ echo $SOME_ENV_VAR
'123' <-- with quotes

但是,如果我直接在 shell 中运行它:

$ export SOME_ENV_VAR='123'
$ echo $SOME_ENV_VAR
123 < -- without quotes

为什么会这样?为什么使用$() 运行命令和直接运行有区别?

除此之外:我使用 eval $(gpg -d filename) 让它工作,我不知道为什么会这样。

【问题讨论】:

  • Ubuntu 默认使用 dash 不是吗?你是用 bash 调用脚本吗?
  • 引号在 shell 脚本中的行为与在交互式命令中的行为完全相同。问题是您没有filename 作为脚本运行。提示:$(cat filename)$(echo "export SOME_ENV_VAR='123'") 相同。
  • 这也是BashFAQ #50。顺便说一句,使用 eval 的方式本身就是错误的。至少,添加更多引号:eval "$(gpg -d filename)" - 这样您就不会在将这些操作的结果连接在一起并将结果提供给eval 进行解析之前对解密的内容进行字符串拆分和全局扩展。跨度>

标签: linux bash shell ubuntu


【解决方案1】:

shell 脚本中的引号与 shell 命令中的引号没有区别。

使用$(gpg -d filename.gpg) 语法,您执行的不是shell 脚本,而是常规的单个命令。

你的命令做什么

  1. 它执行gpg -d filename.gpg
  2. 从结果来看,它将第一个(IFS 分隔的)单词作为要执行的命令
  3. 它将每个其他(IFS 分隔的)单词(包括来自其他行的单词)作为其参数
  4. 它执行命令

从以下实际示例中,您可以看到它与执行 shell 脚本有何不同:

  1. 从 filename.gpg 中删除单词 export:那么命令是 SOME_ENV_VAR='123',这不被理解为变量赋值(你会得到 SOME_ENV_VAR='123': command not found)。
  2. 如果您添加多行,它们将不会被理解为单独的命令行,而是作为第一个命令的参数 (export)。
  3. 如果将export SOME_ENV_VAR='123'改为export SOME_ENV_VAR=$PWD,SOME_ENV_VAR将不会包含变量PWD的内容,而是字符串$var

为什么会这样?

在分析命令时查看how bash performs expansion

有很多步骤。 $(...) 称为“命令替换”,是第四步。完成后,将不再执行前面的步骤。这解释了为什么当您删除 export 字时您的命令不起作用,以及为什么没有在结果中替换变量。

此外,“引用删除”是最后一步,the manual reads:

所有未加引号的字符‘\’、‘'’和‘"’ 不是由上述扩展之一导致的被删除

由于单引号是由“命令替换”扩展产生的,因此它们没有被删除。这就是为什么 SOME_ENV_VAR 的内容是 '123' 而不是 123

为什么eval 有效?

因为 eval 会触发对其参数的另一次完整解析。整个扩展集再次运行。

From the manual:

参数被连接在一起形成一个命令,然后读取并执行该命令

请注意,这意味着您仍在运行 一个 单个命令,而不是 shell 脚本。如果您的 filename.gpg 脚本有多行,后续行将添加到第一个(也是唯一一个)命令的参数列表中。

那我该怎么办?

只需使用 sourceprocess substitution

source <(gpg -d filename.gpg)

eval相反,source用于在当前上下文中执行一个shell脚本。进程替换提供了一个包含替换结果的伪文件名(即gpg 的输出)。

【讨论】:

猜你喜欢
  • 2018-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多