如何在 Ruby 脚本中为命令 shell 获取环境变量?

Posted

技术标签:

【中文标题】如何在 Ruby 脚本中为命令 shell 获取环境变量?【英文标题】:How do I source environment variables for a command shell in a Ruby script? 【发布时间】:2011-01-09 11:48:36 【问题描述】:

我正在尝试从我的 ruby​​ 程序中运行一些第三方 bash 脚本。

在我可以运行它们之前,它们要求我获取一个文件。在命令行上一切正常,但在 Ruby 中它不起作用。我发现系统命令将打开一个新的子 shell 进程,并且任何采购都将在其中完成,并且无法从运行 Ruby 脚本的父 shell 进程中看到。当系统调用结束时,子 shell 也被杀死。

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

修改 ENV 仅适用于单个线程,我改为执行以下操作。 但是我有一个问题,如何将环境的合并副本与 IO.popen 一起使用?不知何故,它似​​乎不起作用。

用“系统”我可以做到:

# ... create new "path" here

    subEnv = Hash.new;
    subEnv.merge!(ENV); # copy old environment
    subEnv['PATH'] = path; # set new values in copy

    system(subEnv, commandLine);

【讨论】:

【参考方案2】:

这太可怕了,但是..

env = %x. /some/shell/script/which/setups/your/env && env
env.split("\n").each do |line|
  key, value = line.split("=", 2)
  ENV[key] ||= value unless value.nil? or value.empty?
end

【讨论】:

这会抓取所有导出的变量。它有效,但这似乎是一种糟糕的行为。【参考方案3】:

我这样做是因为我不想编写文件或将我的 ruby​​ 代码与这些东西混为一谈:

#!/usr/bin/env bash
eval $(echo "$(cat .env) $1" | tr '\n' ' ')

我把它放在 ~/bin/run_with_env.sh 中,然后例如我可以运行:

% run_with_env.sh "rails console"

【讨论】:

【参考方案4】:

我不确定我是否正确理解了您的问题。您是否尝试在运行另一个 shell 脚本之前获取一个 shell 脚本?在这种情况下,答案很简单:

#!/bin/env ruby
system "source <path_to_source_file> && <command>"

如果源文件包含你的命令应该使用的变量,你必须export它们。也可以使用 ENV['&lt;name_of_var&gt;'] = &lt;value&gt; 在 Ruby 脚本中设置环境变量。


更新:2010 年 1 月 26 日 - 15:10

你可以使用 IO.popen 打开一个新的 shell:

IO.popen("/bin/bash", "w") do |shell|
  shell.puts "source <path_to_source_file>"
  shell.puts "<command>"
end

【讨论】:

我不认为使用系统执行会有所帮助,因为 vars 只会为生成执行该命令的 shell 进程设置。 我什至无法让系统“source .bashrc”在我的用户目录中工作。它抱怨找不到命令。您确定可以像您发布的那样使用来源吗? 它对我有用。我在 OSX 10.6 上试过这个。执行脚本的用户的 shell 是否设置为 /bin/bash? (我也更新了我的答案。) 感谢您的回复。我一直在谷歌上搜索,但无法弄清楚为什么我不能在脚本中获取 .bashrc。如何检查 shell 是否设置为 /bin/bash? shell 变量 $SHELL 存储用户的登录 shell。我认为这应该适用于这种特殊情况。但请记住,这是用户登录 shell,因此从 bash shell 运行 /bin/sh -c "echo $SHELL" 之类的内容仍会打印 /bin/bash。【参考方案5】:

这样做:

$ source whatever.sh
$ set > variables.txt

然后在 Ruby 中:

File.readlines("variables.txt").each do |line|
  values = line.split("=")
  ENV[values[0]] = values[1]
end

运行此程序后,您的环境应该可以运行了。

【讨论】:

我试试这个。那么这是否意味着脚本可以更改其包含的 shell 进程的环境变量,从而更改通过继承的系统调用创建的任何其他子进程? 否,但是从 Ruby 脚本执行的任何进程都将继承脚本的变量。 以上适用于单个线程,我执行以下操作。但是我有一个问题,如何将环境的合并副本与 IO.popen 一起使用?不知何故,它似​​乎不起作用。使用“系统”我可以:# ...在此处创建新的“路径” subEnv = Hash.new; subEnv.merge!(ENV); # 复制旧环境 subEnv['PATH'] = path; # 在复制系统中设置新值(subEnv, commandLine); 如果你有一个带有= 的值,这将不起作用(例如URL=http://google.com?q=foo)。 split 采用第二个参数来限制拆分。改为:key, value = line.split "=", 2; ENV[key] = value

以上是关于如何在 Ruby 脚本中为命令 shell 获取环境变量?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Ruby进行shell脚本编写?

如何在Unix中为shell脚本锁定目录[重复]

如何在 Perl/CGI 中为 Web 应用程序创建持久的 shell 命令会话?

如何在PowerShell中连续执行命令

如何从 shell/shell 脚本获取 sqlplus 命令的输出状态?

Shell脚本基础