Executing a system command and stopping it after a specified

I’d like to run a system command and then stop it after specified
amount of time (in seconds or milliseconds.) What’s the best way to
do it?

e.g.

exec(“cat /dev/video > test.mpg”)

then kill the process after so many minutes, seconds, etc…

Also, if there is a better Ruby way to do this other than “cat”, I’m
all ears…

Thanks.

On Apr 14, 9:57 pm, Robert La Ferla [email protected] wrote:

I’d like to run a system command and then stop it after specified
amount of time (in seconds or milliseconds.) What’s the best way to
do it?

In Perl it was done by setting the signal ALRM (or using the “alarm”
command). I’m not sure how this is done in Ruby as I haven’t had a
use for signal trapping since using Ruby.

Also, if there is a better Ruby way to do this other than “cat”, I’m
all ears…

assuming binary file (i.e. mpg)

File.open(“/dev/video”, “rb”) do |inf|
File.open(“test.mpg”, “wb”) do |outf|
inf.each_byte {|byte| outf.putc byte}
end
end

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Robert La Ferla wrote:

ears…

Thanks.

from “ri Timeout”:

require ‘timeout’
status = Timeout::timeout(500) {
exec(“cat /dev/video > test.mpg”)
}

Dan
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGId0kUYnvW+YuEvYRAkc0AKDBBveie/L0/2ePNqkLKYKvqz4fTACgso+d
g3U+yVpF+5pFf3RnGb+fS9o=
=B+zE
-----END PGP SIGNATURE-----

On Apr 14, 9:57 pm, Robert La Ferla [email protected] wrote:

I’d like to run a system command and then stop it after specified
amount of time (in seconds or milliseconds.) What’s the best way to
do it?

Out of curiosity I probed deeper and it looks like you’re looking for
Timeout#timeout (see RDoc/ri for more information). Here is an
example:

require ‘timeout’

raises an exception if timeout is met

begin
Timeout::timeout(5) { sleep 10 }
rescue Timeout::Error
puts “It timed out!”
end

On Apr 15, 2007, at 3:39 AM, Stefan M. wrote:

end
File.open(“test.mpg”, “wb”) do |output|
input.each_byte {|byte| output.putc(byte)}
end
end
end
rescue Timeout::Error
puts(“Done”)
end

Thanks.

A couple of issues:

  1. The time out is working but the “cat” process is not terminated.
    I tried both system(cmd) and #{cmd}.

  2. I wonder if Ruby is fast enough to read /dev/video and dump it to
    a file without a delay. Imagine if this is running for a couple of
    hours…

BTW - My configuration is:

% ruby --version
ruby 1.8.5 (2007-03-13 patchlevel 35) [i386-linux]

Fedora Linux 2.6.20-1.2933.fc6

Robert La Ferla wrote:

I’d like to run a system command and then stop it after specified amount
of time (in seconds or milliseconds.) What’s the best way to do it?

e.g.

exec(“cat /dev/video > test.mpg”)

then kill the process after so many minutes, seconds, etc…

Once you call exec the ruby program does not run anymore.

From the description of Kernel#exec
http://www.ruby-doc.org/core/classes/Kernel.html#M005957

Replaces the current process by running the given external command. If
exec is given a single argument, that argument is taken as a line that
is subject to shell expansion before being executed.

you may want to use

system(“cmd”) module Kernel - RDoc Documentation
cmd module Kernel - RDoc Documentation
%x { cmd }

wrapped in timeout

Also, if there is a better Ruby way to do this other than “cat”, I’m all
ears…

I’m using mencoder ... with options set via string substitution to
record TV-series

channel = ARGV[0]
outfilename = ARGV[1]
duration = ARGV[2]

mencoder dvb://#{channel} -vf lavcdeint -o #{outfilename} -endpos #{duration} -oac lavc -ovc lavc -lavcopts acodec=mp2:vcodec=mpeg2video:vhq:vbitrate=2048

If you want to read from ‘/dev/video’ you could combine james.d.masters
and Dan Z.s suggestions - but using system or `

require “timeout”
begin
Timeout::timeout(600) do
system(“cat /dev/video > test.mpg”)
# cat /dev/video > test.mpg
end
rescue Timeout::Error
puts(“Done”)
end

or

require “timeout”
begin
Timeout::timeout(600) do
File.open(“/dev/video”, “rb”) do |input|
File.open(“test.mpg”, “wb”) do |output|
input.each_byte {|byte| output.putc(byte)}
end
end
end
rescue Timeout::Error
puts(“Done”)
end

Stefan

On Apr 15, 5:30 pm, Robert La Ferla [email protected] wrote:

  1. The time out is working but the “cat” process is not terminated.
    I tried both system(cmd) and #{cmd}.

Maybe you will need to call the “kill” command… I’m not sure if
child processes die with an exception being raised or not.

In any case, I’d use the alternatives mentioned here instead of using
“system”. They are cleaner IMHO.

On Apr 15, 5:57 am, Robert La Ferla [email protected] wrote:

I’d like to run a system command and then stop it after specified
amount of time (in seconds or milliseconds.) What’s the best way to
do it?

I have this handy function ; it raises an exception on timeout/non
zero exit status, returns the result of the call
otherwise (ie. what the process output on $stdout). In case of timeout
it also attemts to kill the process (runs on Unix - no clue about
other platforms!) :

Usage example :

files = run(‘find -mtime -7’)

Function :

def run(s, maxt = 10*60)
begin
pipe = IO.popen(s, ‘r’)
rescue Exception => e
$stderr << ‘Execution of ‘+s+’ has failed :’ + e.to_s
raise “run failed”
end

begin
Timeout::timeout(maxt) do |t|
a = Process.waitpid2(pipe.pid)
if a[1].exitstatus != 0
$stderr << 'Error while executing ’ + s
raise “run failed”
end
end
rescue Timeout::Error => e
$stderr << ‘Execution of ‘+s+’ has timed out. Killing subprocess’
begin
Process.kill(‘KILL’, pipe.pid)
pipe.close
rescue Object => e
$stderr << 'Failed killing process : ’ + e.to_s
end
raise “run failed”
end

out = pipe.gets(nil)
pipe.close
out
end

I’ve edited it a bit to remove some of my specific dependencies - so
there might be typos here :slight_smile:
It could be improved to also return the content of $stderr in case of
non-zero exit status.

Anselm

On Mon, 16 Apr 2007, Robert La Ferla wrote:

system(“cat /dev/video > test.mpg”)
Timeout::timeout(600) do
Thanks.
BTW - My configuration is:

% ruby --version
ruby 1.8.5 (2007-03-13 patchlevel 35) [i386-linux]

Fedora Linux 2.6.20-1.2933.fc6

require ‘rubygems’
require ‘open4’ ### gem install open4

Open4.spawn ‘cat /dev/video’, :timeout=>600, :stdout=>buf=’’

p buf.size

-a