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

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

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

我该如何解决这个问题?

【问题讨论】:

    标签: ruby environment-variables


    【解决方案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
        猜你喜欢
        • 1970-01-01
        • 2017-02-22
        • 2014-03-29
        • 2023-04-01
        • 2015-05-07
        • 2011-10-13
        • 1970-01-01
        • 2013-08-25
        相关资源
        最近更新 更多