我如何捕获 shell 变量输出以用于我的 capistrano 任务

我如何捕获 shell 变量输出以用于我的 capistrano 任务

我正在使用 capistrano 部署 Ruby on Rails 应用程序。我以前使用的是 Centos。在将我的任务转换为与 Ubuntu 一起使用时,我有一个用于 Centos 的任务是:

 capture("env | grep ENV_VAR").split("=").last

这将捕获远程系统上该变量的输出,以供我的代码使用。但是,此代码似乎不适用于 Ubuntu。有人能告诉我如何使用 capistrano 和 ubuntu 捕获变量的输出吗?

我努力了

capture("echo $ENV_VAR")

但这样会打印出一个空字符串。我假设问题与“$”有关,但我不确定。

提前感谢任何帮助。

答案1

使用printenv反而,它不需要 shell:

capture('printenv ENV_VAR')

代替ENV_VAR替换为所需环境变量的名称。不要在前面添加$

虽然printenv非 POSIXGNU/LinuxDebian、Ubuntu、Fedora 和 CentOS 等系统支持它,因为GNU 核心实用程序提供它,并且它适用于许多其他 *nix 系统printenv,就像 FreeBSD 一样。你需要使用而不是的原因env是输出的值printenv ENV_VARENV_VAR,同时尝试运行一个名为env ENV_VARENV_VAR,这不是您想要的。


本文的其余部分介绍了其他方法、它们的局限性以及如何改进它们。这是可选阅读,因为它printenv很简单,而且完全解决了问题。

你原来的方法,,即使在系统上也不应该使用capture("env | grep ENV_VAR").split("=").last似乎行不通,因为它不可靠。它对行grep中所有位置的变量名称都适用VAR=val,因此将返回名称(甚至值)为包含所需变量的名称。使用而不是^ENV_VAR=ENV_VAR解决了这个问题,只在名称出现在行首( ^) 并要求=字符紧随其后。但是,价值环境变量包含一个=字符,由于您调用splitlast,因此您实际上获取了不包含的值的最长尾随子字符串=。即使您修复了这个问题,当您只需要时,该方法仍然不必要地复杂printenv

您找到的解决方案,, 将工作capture("/bin/sh -c 'echo $ENV_VAR'")大多数时候,但当变量(A)包含除单个空格字符之外的空格,且周围有非空格,或者(二)包含通配符例如*?如果[它们恰好与任何文件名匹配。问题是,在 shell 命令中,echo $ENV_VAR参数扩展 $ENV_VAR不是, 所以单词拆分通配符执行。echo重新插入空格,但方式并不总是相同:echo foo bar打印foo bar,但也是如此echo foo bar。可以通过在扩展周围放置引号来解决此问题"",尽管您必须转义他们因此 Ruby 解释器不会将它们视为结束"-quote 字符串并开始一个新字符串,或者您可以'-quote Ruby 字符串并转义任何内部'字符。

在不太常见的情况下,你也会得到错误的结果,即ENV_VAR以支持的选项开头echo。不同的echo实现支持不同的选项;-n-e很常见。大多数 shell 都具有echo内置选项,并且可能支持与其他 shell 和 不同的选项/bin/echo。也就是说echo便携性不强. 以交互方式检查环境变量是合理的,这时您可能会意识到是否发生了奇怪的事情,但对于脚本来说则不然。echo的可移植性问题因/bin/sh并非总是如此而加剧bash在 Ubuntu 中是这样的dash可以通过使用printf '%s\n'printf "%s\n"代替echo(或者,在您的情况下,printf %s可能就足够了)来避免这种情况。

因此,您的解决方案可以改进为。对于不了解 Ruby 的经验丰富的 shell 脚本编写者来说,这可能看起来是错误的;请注意,与 Bash 和其他 Bourne 风格的 shell 不同,Ruby 将其视为-quoted 字符串内的文字。即使它是正确的,您的同事也必须查看两次才能确定这一点,即使他们精通 Ruby 和 shell 脚本。更简单。capture('/bin/sh -c \'printf "%s\n" "$ENV_VAR"\'')\''''capture('printenv ENV_VAR')

答案2

我终于偶然发现了这个答案。实现此目的的方法是加载 bash shell 并将命令传递给它。

capture("/bin/sh -c 'echo $ENV_VAR'")

相关内容