Capturing System Call Return Values?

T

Tyler Knappe

I'm attempting to use Ruby to make system calls (in this case python
scripts) which return values, that I then hand off to Ruby on Rails to
populate a webpage. However, I've run into a problem with capturing the
return values of system calls.

Using system () only returns whether the command was executed
successfully.

Using `[system call]` captures stdout, which works, but only if I then
chomp on the string returned. I would then have to make some
assumptions about the size of each value returned (I really see this
being error prone).

Using systemu (http://codeforpeople.com/lib/ruby/systemu/) allows me to
capture stdout, stderror, and status. Not returned values.

One work around is to call multiple python scripts, but this could
become very expensive very fast, because I'm querying a database (plus
one call returns all the values I need).

Ideally, I would be able to return an array of values from my python
script then use them in ruby to populate the webpage. Is this possible?
 
R

Robert Klemme

The term "system call" is usually used to denote calls of functions in
the system library (e.g. open(), read(), fork()). What you mean would
rather be called an "external process". (Of course that's done via a
system call as well, but this is just one of a multitude of available
system calls.)
$? exit status of last executed child process

I don't think is quite correct. I tried it and was returned a value of
0.

Why would that mean that the statement above is not correct?
I've found a work around by splitting the returned string using
[string].split(' ') but this isn't as elegant as I had hoped.

Now I am not sure what you want: are you interested in the exit status
of a process that was executed? E.g.

irb(main):010:0> system "false"
=> false
irb(main):011:0> $?
=> #<Process::Status: pid 4008 exit 1>
irb(main):012:0> system "echo", "test"
test
=> true
irb(main):013:0> $?
=> #<Process::Status: pid 1228 exit 0>
irb(main):014:0>

Or do you mean the output of an external process, e.g.

irb(main):001:0> dir = `ls -dl`
=> "drwxrwxrwt+ 2 robert Benutzer 0 Jun 19 21:53 .\n"
irb(main):002:0>

Your last statement seems to indicate the latter.

Kind regards

robert
 
L

list. rb

class Task
attr_accessor :cmd, :pid, :eek:utput, :exitstatus, :thread
def initialize(cmd)
@cmd =3D cmd
queue =3D Queue.new
@Thread =3D Thread.new(queue) {|q|
pipe =3D IO.popen(cmd + " 2>&1")
q.push(pipe)
q.push(pipe.pid)
self.pid =3D pipe.pid
begin
self.output =3D pipe.readlines
pipe.close
self.exitstatus =3D $?.exitstatus
rescue =3D> e
q.push e
end
}
queue.clear
end
def join
thread.join
end
end

task =3D Task.new("ruby -e 'sleep 3 and puts Time.now'")
task.join
p task

The term "system call" is usually used to denote calls of functions in th= e
system library (e.g. open(), read(), fork()). What you mean would rather= be
called an "external process". (Of course that's done via a system call a= s
well, but this is just one of a multitude of available system calls.)

that I then hand off to Ruby on Rails to agell/ruby/globalvars.html+ruby+global+variables&cd=3D1&hl=3Den&ct=3Dclnk&g=
l=3Dus&client=3Dfirefox-a<http://74.125.155.132/search?q=3Dcache:lNLxDxyXbj=
4J:www.rubyist.net/%7Eslagell/ruby/globalvars.html+ruby+global+variables&cd=
=3D1&hl=3Den&ct=3Dclnk&gl=3Dus&client=3Dfirefox-a>
$? exit status of last executed child process

I don't think is quite correct. I tried it and was returned a value of = 0.

Why would that mean that the statement above is not correct?

I've found a work around by splitting the returned string using
[string].split(' ') but this isn't as elegant as I had hoped.

Now I am not sure what you want: are you interested in the exit status of= a
process that was executed? E.g.

irb(main):010:0> system "false"
=3D> false
irb(main):011:0> $?
=3D> #<Process::Status: pid 4008 exit 1>
irb(main):012:0> system "echo", "test"
test
=3D> true
irb(main):013:0> $?
=3D> #<Process::Status: pid 1228 exit 0>
irb(main):014:0>

Or do you mean the output of an external process, e.g.

irb(main):001:0> dir =3D `ls -dl`
=3D> "drwxrwxrwt+ 2 robert Benutzer 0 Jun 19 21:53 .\n"
irb(main):002:0>

Your last statement seems to indicate the latter.

Kind regards

robert
 
L

list. rb

class Task
attr_accessor :cmd, :pid, :eek:utput, :exitstatus, :thread
def initialize(cmd)
@cmd =3D cmd
queue =3D Queue.new
@thread =3D Thread.new(queue) {|q|
pipe =3D IO.popen(cmd + " 2>&1")
q.push(pipe)
q.push(pipe.pid)
self.pid =3D pipe.pid
begin
self.output =3D pipe.readlines
pipe.close
self.exitstatus =3D $?.exitstatus
rescue =3D> e
q.push e
end
}
queue.clear
end
def join
thread.join
end
end

task =3D Task.new("ruby -e 'sleep 3 and puts Time.now'")
task.join
p task

The term "system call" is usually used to denote calls of functions in the
system library (e.g. open(), read(), fork()). What you mean would rath=
er
be
called an "external process". (Of course that's done via a system call as
well, but this is just one of a multitude of available system calls.)

that I then hand off to Ruby on Rails to http://74.125.155.132/search?q=3Dcache:lNLxDxyXbj4J:www.rubyist.net/~slag=
ell/ruby/globalvars.html+ruby+global+variables&cd=3D1&hl=3Den&ct=3Dclnk&gl=
=3Dus&client=3Dfirefox-a<http://74.125.155.132/search?q=3Dcache:lNLxDxyXbj4=
J:www.rubyist.net/%7Eslagell/ruby/globalvars.html+ruby+global+variables&cd=
=3D1&hl=3Den&ct=3Dclnk&gl=3Dus&client=3Dfirefox-a>
agell/ruby/globalvars.html+ruby+global+variables&cd=3D1&hl=3Den&ct=3Dclnk&g=
l=3Dus&client=3Dfirefox-a f
0.
Why would that mean that the statement above is not correct?

I've found a work around by splitting the returned string using
[string].split(' ') but this isn't as elegant as I had hoped.

Now I am not sure what you want: are you interested in the exit status =
of
a
process that was executed? E.g.

irb(main):010:0> system "false"
=3D> false
irb(main):011:0> $?
=3D> #<Process::Status: pid 4008 exit 1>
irb(main):012:0> system "echo", "test"
test
=3D> true
irb(main):013:0> $?
=3D> #<Process::Status: pid 1228 exit 0>
irb(main):014:0>

Or do you mean the output of an external process, e.g.

irb(main):001:0> dir =3D `ls -dl`
=3D> "drwxrwxrwt+ 2 robert Benutzer 0 Jun 19 21:53 .\n"
irb(main):002:0>

Your last statement seems to indicate the latter.

Kind regards

robert



Whoops, I top posted


class Task
attr_accessor :cmd, :pid, :eek:utput, :exitstatus, :thread
def initialize(cmd)
@cmd =3D cmd
queue =3D Queue.new
@Thread =3D Thread.new(queue) {|q|
pipe =3D IO.popen(cmd + " 2>&1")
q.push(pipe)
q.push(pipe.pid)
self.pid =3D pipe.pid
begin
self.output =3D pipe.readlines
pipe.close
self.exitstatus =3D $?.exitstatus
rescue =3D> e
q.push e
end
}
queue.clear
end
def join
thread.join
end
end

task =3D Task.new("ruby -e 'sleep 3 and puts Time.now'")
task.join
p task
 
D

Delano Mandelbaum

I've found a work around by splitting the returned string using
[string].split(' ') but this isn't as elegant as I had hoped.

I wrote a library called Rye to solve this problem. It might be some
like what you're looking for. Here's an example of running local
external processes:

ret = Rye.shell('script.py', 'arg1', 'arg2')
p ret.stdout # => ['line1', 'line2']
p ret.exit_code # => 0
p ret.stderr # => nil
p ret.class # => Rye::Rap

There is also an object oriented interface for executing remote
processes via SSH.

Codes: http://github.com/delano/rye/
RDocs: http://rye.rubyforge.org/

Delano
 
L

list. rb

[Note: parts of this message were removed to make it a legal post.]

One thin wanted to do but never got around to it - was to return the output
in a call back as each line was written to..

I've found a work around by splitting the returned string using
[string].split(' ') but this isn't as elegant as I had hoped.

I wrote a library called Rye to solve this problem. It might be some
like what you're looking for. Here's an example of running local
external processes:

ret = Rye.shell('script.py', 'arg1', 'arg2')
p ret.stdout # => ['line1', 'line2']
p ret.exit_code # => 0
p ret.stderr # => nil
p ret.class # => Rye::Rap

There is also an object oriented interface for executing remote
processes via SSH.

Codes: http://github.com/delano/rye/
RDocs: http://rye.rubyforge.org/

Delano
 
L

list. rb

[Note: parts of this message were removed to make it a legal post.]
One thin wanted to do but never got around to it - was to return the
output in a call back as each line was written to..


I've found a work around by splitting the returned string using
[string].split(' ') but this isn't as elegant as I had hoped.

I wrote a library called Rye to solve this problem. It might be some
like what you're looking for. Here's an example of running local
external processes:

ret = Rye.shell('script.py', 'arg1', 'arg2')
p ret.stdout # => ['line1', 'line2']
p ret.exit_code # => 0
p ret.stderr # => nil
p ret.class # => Rye::Rap

There is also an object oriented interface for executing remote
processes via SSH.

Codes: http://github.com/delano/rye/
RDocs: http://rye.rubyforge.org/

Delano


Second attempt at correcting a top post ;-) grrrmail

One thin wanted to do but never got around to it - was to return the output
in a call back as each line was written to..
 
D

Delano Mandelbaum

One thin wanted to do but never got around to it  - was to return the output
in a call back as each line was written to..

That's coming in Rye 0.9 :] (currently 0.7.6)
 
T

Tyler Knappe

Why would that mean that the statement above is not correct?

Revisiting this, here is what I am trying to do:

path = "python [..path..]/test.py"

print path + "\n"

test = %x[python [..path..]/test.py]

print test

testing = %x[uptime]

print testing


Here is the output:

python [..path..]/test.py
Testing! my script
2nd line
8:20am up 181 days 20:55, 7 users, load average: 0.00, 0.00, 0.00

However, what I was expecting from the test variable was this:

print "Testing! my script "
print "2nd line"

def returnValue():
return True

returnValue()

Where I was expecting to see test = True. The return value of the
system call is not being capture when I call a python script, yet IS
when a 'system call' is made.

Anyone have any insight into this?
 
R

Roger Pack

Anyone have any insight into this?

Hmm.
(irb):1: command not found: bad
=> ""=> false
irb(main):004:0> $?
=> #<Process::Status: pid=27335,exited(127)>

Appears a little buggy on windows for some reason.

C:\dev\blade_copy>irb=> #<Process::Status: pid=0,exited(127)> # and now it's right. Odd.

-=r
 
T

Tyler Knappe

Roger said:
Hmm.

(irb):1: command not found: bad
=> ""
=> false
irb(main):004:0> $?
=> #<Process::Status: pid=27335,exited(127)>

Appears a little buggy on windows for some reason.

C:\dev\blade_copy>irb
=> #<Process::Status: pid=0,exited(127)> # and now it's right. Odd.

-=r

irb(main):008:0> path = "python [..path..]/test.py" => "python
[..path..]/test.py"
irb(main):009:0> test = %x[#{path}]
=> "Testing! my script \n2nd line\n"
irb(main):010:0> test
=> "Testing! my script \n2nd line\n"
irb(main):011:0> $?
=> #<Process::Status: pid=22782,exited(0)>
irb(main):012:0> test = `python [..path..]/test.py`
=> "Testing! my script \n2nd line\n"
irb(main):013:0> test
=> "Testing! my script \n2nd line\n"
irb(main):014:0> $?
=> #<Process::Status: pid=22826,exited(0)>
irb(main):015:0>

test =/= True in either case, which is what I was looking for, nor is
$?.
 
R

Roger Pack

irb(main):008:0> path = "python [..path..]/test.py" => "python
[..path..]/test.py"
irb(main):009:0> test = %x[#{path}]
=> "Testing! my script \n2nd line\n"
irb(main):010:0> test
=> "Testing! my script \n2nd line\n"
irb(main):011:0> $?
=> #<Process::Status: pid=22782,exited(0)>
irb(main):012:0> test = `python [..path..]/test.py`
=> "Testing! my script \n2nd line\n"
irb(main):013:0> test
=> "Testing! my script \n2nd line\n"
irb(main):014:0> $?
=> #<Process::Status: pid=22826,exited(0)>
irb(main):015:0>

test =/= True in either case, which is what I was looking for, nor is
$?.

So did that answer your question? If not maybe you can help me
understand more what was trying to happen here.
Cheers.
-=r
 
T

Tyler Knappe

Roger said:
irb(main):008:0> path = "python [..path..]/test.py" => "python
[..path..]/test.py"
irb(main):009:0> test = %x[#{path}]
=> "Testing! my script \n2nd line\n"
irb(main):010:0> test
=> "Testing! my script \n2nd line\n"
irb(main):011:0> $?
=> #<Process::Status: pid=22782,exited(0)>
irb(main):012:0> test = `python [..path..]/test.py`
=> "Testing! my script \n2nd line\n"
irb(main):013:0> test
=> "Testing! my script \n2nd line\n"
irb(main):014:0> $?
=> #<Process::Status: pid=22826,exited(0)>
irb(main):015:0>

test =/= True in either case, which is what I was looking for, nor is
$?.

So did that answer your question? If not maybe you can help me
understand more what was trying to happen here.
Cheers.
-=r

No, I had expected to see test == True, as my python script returns
True. All I see is ruby capturing all stdout and storing it in test.

I can see where the confusion is coming in, lets say my python script
instead of returning true, returns an array of values. I want test to
equal that array of values.
 
R

Roger Pack

Where I was expecting to see test = True. The return value of the
system call is not being capture when I call a python script, yet IS
when a 'system call' is made.

I think the confusion comes from this:
Testing! my script
2nd line
=> true

that last true means "the command returned a value of 0" and is a ruby
true

if you want the output *and* its success value then you'll need to use
%x[python test.py] => "Testing! my script \n2nd line\nTrue\n"
$?.exitstatus == 0
=> true

There's your true.

If you want to get the last thing the python script outputs then
[pretend last line is "print returnValue()"]

it'll be something like %x[python test.py].split("\n")[-1]

Maybe one of those will help you. Or use Rye which appears to do that
in a class oriented way.
-=r
 
D

Douglas Seifert

[Note: parts of this message were removed to make it a legal post.]
No, I had expected to see test == True, as my python script returns
True. All I see is ruby capturing all stdout and storing it in test.

I can see where the confusion is coming in, lets say my python script
instead of returning true, returns an array of values. I want test to
equal that array of values.
You are expecting a program written in one language to return objects to a
calling program written in another language ... sorry to say, but it just
doesn't work that way. It certainly would be nice, though, I have to admit.

The closest you are going to get is to get the python program to print out a
string of valid ruby code, make the calling ruby code somehow extract this
line of output from all the other potential lines of output the python
program might generate and then maybe eval it in the calling program.

Or maybe somebody has written some CORBA bindings for ruby? Ha, ha, just
kidding ... ;)

Good luck ...

-Doug Seifert
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top