繁体   English   中英

如何将环境变量从Shell脚本导入当前的Ruby环境?

[英]How can I import environment variables from a shell script into the current Ruby environment?

我有一系列bash文件,我想将它们提供给当前的Ruby环境。 这是一个例子:

$ echo "export FOO=bar" > foo.sh
$ irb
> `source $(pwd)/foo.sh`
> puts ENV['FOO']
=> nil

有没有一种方法可以将foo.sh来源到父环境中而无需手动解析它?

Ruby中的所有shell调用都在子Process中运行,无论您使用system()还是反引号,还是使用Process或任何其他机制来执行它们。 像这样的子流程不可能影响当前的Ruby流程。

如果要在执行某些Ruby代码之前先获取Shell脚本,则可以创建包装器:

#!/bin/sh

source foo.sh
ruby some_ruby_file.rb

如果确实需要,您可以尝试从shell脚本中解析出变量导出,然后直接设置Ruby的ENV哈希,但这几乎肯定是个坏主意。 很难编写,容易出错且难以维护。

可以使用上述包装器,也可以使用其他方法保存环境配置,例如YAML文件或其他常规配置解决方案。

TL; DR

您不能从子进程或子Shell更改父进程的环境,但是可以肯定地将文件来源或解析为当前进程。

“来源”一个Ruby脚本

您可以使用Kernel#loadKernel#require方法来获取Ruby脚本。 这会将文件的内容导入到您当前的进程中。

将Shell脚本解析为Ruby

如果您的源文件是shell脚本,则不能简单地将其作为Ruby加载; 您将需要执行某种类型的文件解析。 除非您信任所读取文件的内容,格式和源,否则这可能会带来安全风险。

假设您信任您的输入源,并给出了一个示例文件,例如:

#!/usr/bin/bash

export FOO='bar'
echo FOO
echo bar
echo "FOO=$FOO"

您可以执行以下操作:

# Find variables in the general form of "export x=y" 
env_vars = File.read('/tmp/file.txt').scan /export\s+(\S+)=(\S+)/
#=> [["FOO", "'bar'"]]

# Parse each variable into the Ruby ENV key/value pair, removing
# outer quotes on the value if present.
env_vars.each { |v| ENV[v.first] = v.last.gsub /\A['"]|['"]\Z/, '' }

# Verify you have the value you expect.
ENV['FOO']
#=> "bar"

这会将通过String#scan方法找到的每个变量添加到ENV中 ,然后可以通过其键对其进行访问。

解析注意事项

  • 这在临时测试中可以很好地工作,但是如果您没有在定义变量的同一行上导出变量,则可能需要修改正则表达式。
  • 此外,还需要清理或验证输入。
  • 我强烈建议您仅设置您希望看到的环境变量(例如,使用Array#select将可接受的ENV密钥列入白名单),并确保为您设置的每个变量的值对于您的特定用例而言都是合理且安全的。

期权的更好选择

通常,如果您尝试从脚本内部设置配置选项,则最好加载YAML文件或使用OptionParser 特别是YAML文件易于阅读,易于解析,可人工编辑以及(相对)易于清理。 你的旅费可能会改变。

我几乎得到了一些答案,但没有一个完全适合我的情况,这就是我最终要做的事情:

file = Pathname.new "tmp-variables.txt"
`env -i /bin/sh -c 'source <myfile-here.sh> && env > #{file}'`
file.each_line do |line|
  line.match(/(?<key>[^=]+)=(?<value>.+)/) {|match| ENV[match[:key]] = match[:value] }
end

这是一个示例脚本,显示了它的运行情况:

require 'pathname'

file = Pathname.new "tmp-variables.txt"
`mkdir profile.d`
`echo "export FOO=${FOO:-'bar'}" > profile.d/node`
`touch #{file}`
`env -i /bin/sh -c 'source profile.d/node && env > #{file}'`
file.each_line do |line|
  line.match(/(?<key>[^=]+)=(?<value>.+)/) {|match| ENV[match[:key]] = match[:value] }
end
puts ENV['FOO']

这里的一些技巧env -i在没有任何环境变量的情况下执行命令( -c )。 我尝试使用此技巧, 如何在Ruby脚本中为命令外壳提供环境变量? 但是set给您所有的环境变量,我只想要那个文件中的那些。

吉姆的想法很好,但由于我的限制而无法使用。 CodeGnome在正确的路径上,但是如果不进行评估就无法批发阅读文件,否则我们会误认为file = Pathname.new "tmp-variables.txt" 谢谢大家,这是团队的共同努力。 我已经给你们所有人投票了。

您可以使用dotenv gem导入.env文件。

https://github.com/bkeepers/dotenv

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM