Как изменить исходные переменные среды для командной оболочки в Ruby script?

Я пытаюсь запустить некоторые сторонние скрипты bash из моей рубиновой программы.

Прежде чем я смогу запустить их, они потребуют от меня файла. В командной строке все работает нормально, но внутри Ruby это не работает. Я узнал, что системные команды откроют новый процесс дочерней оболочки, и любой источник будет выполнен в этом и не будет видно из процесса родительской оболочки, запускающего Ruby script. Когда системный вызов завершается, дочерняя оболочка также убивается.

Как обойти эту проблему?

Ответ 1

Сделайте это:

$ source whatever.sh
$ set > variables.txt

И затем в Ruby:

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

После того, как вы запустили это, ваша среда должна быть хорошей.

Ответ 2

Я не уверен, правильно ли понимаю ваш вопрос. Вы пытаетесь запустить оболочку script перед запуском другого? В этом случае ответ прост:

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

Если исходный файл содержит переменные, которые ваша команда должна использовать, вы должны иметь export их. Также возможно установить переменные среды в Ruby script с помощью ENV['<name_of_var>'] = <value>.


Обновление: 26 января 2010 г. - 15:10

Вы можете использовать IO.popen для открытия новой оболочки:

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

Ответ 3

Это ужасно, но..

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

Ответ 4

Я сделал это, потому что я не хотел писать файл или смешивать свой рубиновый код с этим материалом:

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

Я помещаю это в ~/bin/run_with_env.sh, а затем, например, могу запустить:

% run_with_env.sh "rails console"

Ответ 5

Изменение 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);