shell command with envvars - howto?

W

Wybo Dekker

I want to make a system calling method that returns output, success rate,
and exit status of a system command, like the sys method in the example
program below. My system call fails, however, when I put a definition of an
environment variable in front of the system command.

It works only if I put &&'s between the envvar definition(s) and the
command, as illustrated in the program. But that means that I'll have to
interpret the argument of my method to insert those &&'s.

Is there a better way?

#!/usr/bin/env ruby

# return output, success rate, and exit status of a system command
def sys(command)
[%x{#{command} 2>&1}, $?.success?, $?.exitstatus]
end

def pr(command,output,success,status)
puts "command: #{command}"
puts " output: #{output}"
puts "success: #{success ? 'succeeded' : 'failed'}"
puts " status: #{status}",''
end

command = "echo hello"; pr(command,*sys(command))
command = "xxxx hello"; pr(command,*sys(command))
command = "x=hello echo $x"; pr(command,*sys(command)) # FAILS!
command = "x=hello && echo $x"; pr(command,*sys(command))

Outputs:

command: echo hello
output: hello
success: succeeded
status: 0

command: xxxx hello
output: sh: xxxx: command not found
success: failed
status: 127

command: x=hello echo $x
output:
success: succeeded
status: 0

command: x=hello && echo $x
output: hello
success: succeeded
status: 0
 
R

Reyn Vlietstra

------=_Part_2891_5232449.1125399954990
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hi,
We havent implemented && or exit status yet(shouldnt be too hard using=20
open4), but have a look at ruSH.

You can pipe commands to each other.

http://reyn.co.za/rushtest2.png
http://rubyforge.org/projects/rush/


=20
I want to make a system calling method that returns output, success rate,
and exit status of a system command, like the sys method in the example
program below. My system call fails, however, when I put a definition of= =20
an
environment variable in front of the system command.
=20
It works only if I put &&'s between the envvar definition(s) and the
command, as illustrated in the program. But that means that I'll have to
interpret the argument of my method to insert those &&'s.
=20
Is there a better way?
=20
#!/usr/bin/env ruby
=20
# return output, success rate, and exit status of a system command
def sys(command)
[%x{#{command} 2>&1}, $?.success?, $?.exitstatus]
end
=20
def pr(command,output,success,status)
puts "command: #{command}"
puts " output: #{output}"
puts "success: #{success ? 'succeeded' : 'failed'}"
puts " status: #{status}",''
end
=20
command =3D "echo hello"; pr(command,*sys(command))
command =3D "xxxx hello"; pr(command,*sys(command))
command =3D "x=3Dhello echo $x"; pr(command,*sys(command)) # FAILS!
command =3D "x=3Dhello && echo $x"; pr(command,*sys(command))
=20
Outputs:
=20
command: echo hello
output: hello
success: succeeded
status: 0
=20
command: xxxx hello
output: sh: xxxx: command not found
success: failed
status: 127
=20
command: x=3Dhello echo $x
output:
success: succeeded
status: 0
=20
command: x=3Dhello && echo $x
output: hello
success: succeeded
status: 0
=20
=20
=20


--=20
Reyn Vlietstra

------=_Part_2891_5232449.1125399954990--
 
A

Ara.T.Howard

command = "x=hello echo $x"; pr(command,*sys(command)) # FAILS!

this doesn't even work from the shell:

harp:~ > x=hello echo $x
(newline)

this is because parameter expansion (of $x) occurs __before__ the x=hello is
set for the local environment. you can see this by doing:

harp:~ > x=hello env|egrep ^x=
x=hello

so here the 'x' is looked for __after__ local env vars are set. this is
detailed here:

http://www.gnu.org/software/bash/manual/bashref.html#SEC48

alternatives:

using session:

harp:~ > cat a.rb
require 'session'

sh = Session::new

sh.execute 'x=hello'
stdout, stderr = sh.execute 'echo $x'

p stdout
p sh.status

harp:~ > ruby a.rb
"hello\n"
0


another way:

def sys cmd, env = {}
merge_env(env){ [ %x[{ #{ cmd } ;} 2>&1], $?.success?, $?.exitstatus ]}
end
def merge_env new_env, &block
push_env(ENV.to_hash.merge(new_env), &block)
end
def push_env new_env, &block
@env_stack ||= []
cur_env = ENV.to_hash
@env_stack << cur_env
set_env new_env
if block
begin
block[new_env]
ensure
pop_env
end
else
cur_env
end
end
def pop_env
@env_stack ||= []
old_env = @env_stack.pop
if old_env
set_env old_env
else
old_env
end
end
def set_env env
ENV.clear
env.each{|k,v| ENV["#{ k }"] = "#{ v }"}
ENV.to_hash
end


use like

sys 'foobar', 'PATH' => './bin', 'LD_LIBRARY_PATH' => './lib'

hth.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze. --Nagarjuna
===============================================================================
 
P

Patrick Gundlach

Hello Wybo,

I am not sure if this might break anything, but try inserting a ';'
after your assignment:

command = "x=hello ; echo $x"; pr(command,*sys(command))

Patrick
 
W

Wybo Dekker

Ara.T.Howard said:
this doesn't even work from the shell:

harp:~ > x=hello echo $x
(newline)

You're quite right - I have been totally confused and made the wrong test!
Thanks for helping me out. Thanks also for pointing me to session.rb, which
allows me to get output to stdout and stderr separately.
 

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,774
Messages
2,569,598
Members
45,149
Latest member
Vinay Kumar Nevatia0
Top