我有一系列bash文件,我想在当前的Ruby环境中获取。这是一个例子:
$ echo "export FOO=bar" > foo.sh
$ irb
> `source $(pwd)/foo.sh`
> puts ENV['FOO']
=> nil
有没有办法将foo.sh
导入父环境而无需手动解析它?
答案 0 :(得分:2)
Ruby中的所有shell调用都在子进程中运行,无论是使用system()
还是使用反引号或Process
或任何其他机制来执行它们。像这样的子进程不可能影响当前的Ruby进程。
如果要在执行某些Ruby代码之前获取shell脚本,可以创建一个包装器:
#!/bin/sh
source foo.sh
ruby some_ruby_file.rb
如果你真的想,你可以尝试解析shell脚本中的变量导出,然后直接设置Ruby的ENV
哈希,但这几乎肯定是个坏主意。它很难写,容易出错,而且不可维护。
使用上面的包装器,或者以不同的方式保存环境配置,例如YAML文件或其他传统配置解决方案。
答案 1 :(得分:2)
您无法从子进程或子shell更改父进程的环境,但您当然可以将文件源或解析为当前进程。
您可以使用Kernel#load或Kernel#require方法获取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,然后可以通过其密钥访问它。
通常,如果您尝试从脚本内部设置配置选项,最好加载YAML file或使用OptionParser。特别是YAML文件易于阅读,易于解析,人类可编辑,并且(相对)易于消毒。您的里程可能会有所不同。
答案 2 :(得分:0)
得到几个几乎答案,没有一个完全适用于我的案例,这就是我最终做的事情:
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
)而没有任何环境变量。我尝试使用此技巧How do I source environment variables for a command shell in a Ruby script?,但set
为您提供所有环境变量,我只想要该文件中的那些。
Jim的想法很好,但由于我的限制而无法使用。 CodeGnome是在正确的道路上,但我们不能在没有评估的情况下阅读文件,否则我们会错误地使用file = Pathname.new "tmp-variables.txt"
之类的东西。谢谢大家,这是团队的努力。我已经把你所有的选票都给了你。
答案 3 :(得分:0)
您可以使用dotenv gem导入.env文件。