Ruby and *NIX environment variables

B

Ben Zealley

'allo,

Context: I'm replacing parts of an existing collection of shell scripts
and bits of Perl with a unified Ruby system (this despite little to no
understanding of either of the first two...). In one particular case, I
have a script (values.sh) which contains instructions like

VARIABLE=VALUE

The results of which I would really like to be able to see from Ruby.
I'm told that it's setting environment variables and that the values
are visible from the calling script because it invokes values.sh with a
leading period, which causes them to share an environment - fair
enough.

The question is this: if I call values.sh from within Ruby (with a
leading period) will I be able to see the updated environment variables
after it returns, or is this behaviour specific to when one shell
script calls another? (They're ksh scripts, if that information is
helpful)

I'd test this myself, but I have no access to any *NIX boxes until I've
completed the design stage of this project... and my history is sadly
Windowsy. :(

Cheers
 
L

Logan Capaldo

The question is this: if I call values.sh from within Ruby (with a
leading period) will I be able to see the updated environment
variables
after it returns, or is this behaviour specific to when one shell
script calls another? (They're ksh scripts, if that information is
helpful)

The second one, fortunately or unfortunately as the case may be. .
<script> is the source command in ksh, it's equivalent to typing the
contents of the shell script in the original file. Theres no why for
a child process to affect it's parent's environment. OTOH if
values.sh has simple value parts you may be able to parse the script
with ruby to pull in the info.
 
A

ara.t.howard

The second one, fortunately or unfortunately as the case may be. . <script>
is the source command in ksh, it's equivalent to typing the contents of the
shell script in the original file. Theres no why for a child process to
affect it's parent's environment. OTOH if values.sh has simple value parts
you may be able to parse the script with ruby to pull in the info.

i do something like this

require 'session'

bash = Session::Bash.new

stdout, stderr = bash.execute 'ruby -r yaml -e" y ENV "'
before = YAML.load stdout

stdout, stderr = bash.execute '. values.sh'

stdout, stderr = bash.execute 'ruby -r yaml -e" y ENV "'
after = YAML.load stdout

updated = after.to_a - before.to_a

updated.each{|k,v| ENV[k] = v}

which saves you having to parse the file and works even if it's horrifically
complicated...

-a
 
L

Logan Capaldo

The second one, fortunately or unfortunately as the case may be. .
<script>
is the source command in ksh, it's equivalent to typing the
contents of the
shell script in the original file. Theres no why for a child
process to
affect it's parent's environment. OTOH if values.sh has simple
value parts
you may be able to parse the script with ruby to pull in the info.

i do something like this

require 'session'

bash = Session::Bash.new

stdout, stderr = bash.execute 'ruby -r yaml -e" y ENV "'
before = YAML.load stdout

stdout, stderr = bash.execute '. values.sh'

stdout, stderr = bash.execute 'ruby -r yaml -e" y ENV "'
after = YAML.load stdout

updated = after.to_a - before.to_a

updated.each{|k,v| ENV[k] = v}

which saves you having to parse the file and works even if it's
horrifically
complicated...
Very neat hack. Only thing I would change would be to do:

...
after = YAML.load stdout
ENV.update(after)
 
B

Ben Zealley

Erm, *puts on his newbie shirt* I don't seem to have the "session"
package, maybe because this is one-click Ruby for Windows - is it
included by default with the *nix version, or do I need to get it from
somewhere? If the latter, where? I assume
http://rubyforge.org/projects/session is the homepage, but there's
nothing there...

Cheers

--
Ben


The second one, fortunately or unfortunately as the case may be. . <script>
is the source command in ksh, it's equivalent to typing the contents of the
shell script in the original file. Theres no why for a child process to
affect it's parent's environment. OTOH if values.sh has simple value parts
you may be able to parse the script with ruby to pull in the info.

i do something like this

require 'session'

bash = Session::Bash.new

stdout, stderr = bash.execute 'ruby -r yaml -e" y ENV "'
before = YAML.load stdout

stdout, stderr = bash.execute '. values.sh'

stdout, stderr = bash.execute 'ruby -r yaml -e" y ENV "'
after = YAML.load stdout

updated = after.to_a - before.to_a

updated.each{|k,v| ENV[k] = v}

which saves you having to parse the file and works even if it's horrifically
complicated...

-a
 
A

ara.t.howard

Erm, *puts on his newbie shirt* I don't seem to have the "session"
package, maybe because this is one-click Ruby for Windows - is it
included by default with the *nix version, or do I need to get it from
somewhere? If the latter, where? I assume
http://rubyforge.org/projects/session is the homepage, but there's
nothing there...

Cheers

it's *nix (or msys or cgywin) specific :

gem install -r session

you don't need session btw. this'll do it too:

harp:~ > cat a.rb
require 'yaml'
require 'tempfile'

def tmpfile txt = ''
t = Tempfile.new rand.to_s
t.write txt
t.close
t.path
end

values_sh = tmpfile %q(
export KEY=VALUE
export date=`date`
export foo=bar
)

def propagate_env path
cmds = <<-cmds
echo __before__; ruby -r yaml -e' y ENV.to_hash '; echo __before__
. #{ path }
echo __after__; ruby -r yaml -e' y ENV.to_hash '; echo __after__
cmds

stdout =
IO.popen('sh', 'w+') do |sh|
sh.write cmds
sh.close_write
sh.read
end

raise "env failure from <#{ path }>" unless $?.exitstatus == 0

before = YAML.load %r/__before__\s*(.*)\s*__before__/mio.match(stdout)[1]
after = YAML.load %r/__after__\s*(.*)\s*__after__/mio.match(stdout)[1]
updated = {}
after.each do |k,v|
updated[k] = v if before[k].nil? or before[k] != after[k]
end
ENV.update updated
updated
end

propagate_env values_sh

p ENV['date']
p ENV['foo']


harp:~ > ruby a.rb
"Tue Jul 25 14:57:06 MDT 2006"
"bar"


regards.


-a
 
B

Ben Zealley

Well, I've bullied them into giving me access to a box, and got Ruby,
RubyGems and session installed and apparently working - by reference to
about three *nix newbie tutorials, but still, it's working :)

In the name of simplicity (my manager is unlikely to be happy with
anything as complex-looking as the second code sample you gave me,
which did work - thankyou!), I'd like to use your original example.

However, I'm getting the following error:

[root@pc2461 ~]# ruby ara.rb
ara.rb:18: warning: default `to_a' will be obsolete
ara.rb:18: warning: default `to_a' will be obsolete
ara.rb:22:in `[]=': can't convert Object into String (TypeError)
from ara.rb:22
from ara.rb:22

I've tried playing around a bit but I can't seem to get much more than
that. Although "updated" ends up as an Array it only contains one value
(which is just of type Object, and doesn't correspond to any obvious
objects like "nil"...). (I've wrapped the "real" .sh I want to capture
variables from - it sets 8) Do you have any guesses as to why that's
happened?

Thanks so much for taking the time to help me with this!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top