run a subprocess from ruby without waiting for it to return [duplicate] - ruby

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Spawn a background process in Ruby
Spent a couple days poking at this. I was using ruby 1.8.7 from the OS until recently. I would call a subshell with backticks. The subshell was a bash wrapper that would call run any program in the background with stdout and stderr both closed. It then ran disown to let init take over the process and it would return immediately. This worked great for years, where I would have this looping process kick off jobs in the background and immediately report back "yes, it ran, that's all I am telling you".
I upgraded everything to rvm 1.9.3 and everything's fine except for this trick. I'm starting to suspect it's more of a hack than I want to admit. In 1.9.3, I always get an EPIPE error when I spawn that subshell. It says that it has a broken pipe. I can accept that it isn't going to work in 1.9.3 since it seems kinda gross what I was doing in 1.8.7.
I've tried using the system command and I have tried open3:popen2. They also both throw an EPIPE with me calling the disown wrapper.
#!/bin/bash
# this will crash ruby if you keep trying to read from it.
$* >&- &
disown %1
This is the disown wrapper. In ruby I have something like
r=`/usr/local/bin/disown /usr/local/bin/job.sh`
And when this runs, it throws
/usr/local/bin/runner.rb:88:in ``': Broken pipe (Errno::EPIPE)
If I don't assign the (zero) output to the r variable, the effect is identical. And with the system function and Open3:popen2.
So my goal is to simply run a command from ruby and not wait for it to come back. It takes several hours and I do not need to track it, just spawn it. I might try a worker thread pool if it begins to sound like ruby can no longer do this, or if my disown wrapper is too heinous to get any approval. Ok. Thanks.
*edit: Thanks for the great answers everyone. I think Casper showed me that if I had a better handle on the ruby lingo, I probably would have zeroed in on this. Sorry if this a little pedestrian. I appreciate the quick answers, everyone!

Well, you answered yourself: Process.spawn:
Process.spawn("something");

in Ruby 1.9.3, u can use
Process.fork do
# do your long time job
end

Check out the daemons gem. Then you can do:
require 'daemons'
Daemons.run('some_script.rb')

Related

Blocking a bash script running with &

I may have inadvertently launched a bash script containing an infinite cycle whose exit condition may be met next century, if ever. The fact is that I launched the script, as I would do with a nohup program, with
bash [scriptname].sh &
so that (as I get it, which is most probably wrong) I can close the terminal and still keep the script running, as was my intention in developing it. The script should run calculation programmes in my absence and let me gather the results after some time.
Now I want to stop it, but nothing seems to do the trick: I killed the programmes the script had launched, I removed the input file the script was getting orders from and - last and most perfect of accomplishments - I accidentally closed the terminal trying to "exit" the script, which was still giving me error messages.
How can I check whether the script is running (as it does not appear in "top")? Is the '&' relevant? Should I just ask permission to reboot the pc, if that will work and kill everything?
Thank you.
[I put a "Hi everyone" at the beginning but the editor won't let me show it. Oh, well. It's that kind of day.]
Ok, I'll put it right here to prove my stupidity, as I wandered the internet shortly (after a long wandering before writing this post) and found that the line:
kill -9 $(pgrep -f [SCRIPTNAME].sh)
does the trick from any terminal window.
I write this answer to help anyone in the same situation, but feel free to remove the thread if unnecessary (and excuse me for disturbing).
Good you found it, here is another way if you do not use bash -c and run it in current shell not a separate shell.
# put a job in background
sleep 100 &
# save the last PID of background job
MY_PID=$!
# later
kill $MY_PID

Process.spawn (Ruby 1.9.x): How to check if spawning was successful and detect errors?

Using a cross-platform solution (GNU/Linux, Windows), I want to spawn an external program in the background, capture it's pid and later on stop the program via the stored pid.
Consider this code in Ruby 1.9.x:
pid = Process.spawn("xxx")
puts pid
stdout/stderr:
8117
sh: 1: xxx: not found
No exception is thrown, and I don't see any way to detect the fact that the spawn was not successful (xxx is not a valid command).
What is the best way to detect that this spawn was not successful?
Process#spawn returns a process ID. If you get a process ID back, then technically the function itself did not fail. In Ruby >= 2.0.0, Process#spawn will throw Errno::ENOENT if it fails to find the command. As ruby 1.9 is unsupported, the best solution is to upgrade ruby.
A hack which may help would be to test if the process is actually running after the call returns. Sadly, this will be platform specific.
pid = Process.spawn("xxx")
case RUBY_PLATFORM
when /linux/i
success = File.exist?("/proc/#{pid}")
when /windows/i
# use win32api gem, Windows API call EnumProcesses
else
# ?
end
Unfortunately, if the process finishes by the time you test for its existence, you can't tell. You probably want to check for its results (whatever it does) to see if it did it also.
Another approach, if you control the program being launched, is to open a named pipe before launching it and have it send your ruby program a message over the pipe that it is running. You can then read from the pipe after the spawn call in a non-blocking way and use Timeout to prevent it from blocking forever. A simpler, less clean approach would be to have that program write something deterministic to a file that you can use a simple File.exist? test on to see if its there.

Ruby run external program stops script

I have a ruby script that midway through I need it to run another program.
After running the program the rest of the script doesnt get run. For example:
# some ruby that gets run
exe = "Something.exe"
system(exe)
# some ruby that doesnt run
I have also tried using Open3.popen2e(cmd) and Open3.popen3(cmd) but its the same.
Can anyone help me understand what is happening here and how to fix it?
note: I'm using windows
Try to run Something.exe in a new Thread:
Thread.new { system("Something.exe") }
In case you want to run your System.exe asynchronously and continue without waiting it to be finished, you could use spawn or multithreading.
pid = spawn('System.exe')
Process.detach(pid)
According to this previous answer, this should work on Windows as well (while fork or other methods don't).
In this article you can find several examples using system, exec, fork, spawn and Thread on Unix.
I cannot reproduce it, but it could be worth to see if using system("start System.exe") works on windows like system("cmd &") works on UNIX. You can refer to start documentation here.

Piping stdin to ruby script via `myapp | myscript.rb`

I have an app that runs continuously, dumping output from a server and sending strings to stdout. I want to process this output with a Ruby script. The strings are \n-terminated.
For example, I'm trying to run this on the command line:
myapp.exe | my_script.rb
...with my_script.rb defined as:
while $stdin.gets
puts $_
end
I ultimately am going to process the strings using regexes and display some summary data, but for now I'm just trying to get the basic functionality hooked up. When I run the above, I get the following error:
my_script.rb:1:in `gets': Bad file descriptor (Errno::EBADF)
from my_script.rb:1
I am running this on Windows Server 2003 R2 SP2 and Ruby 1.8.6.
How do I continuously process stdin in a Ruby script? (Continuously as in not processing a file, but running until I kill it.)
EDIT:
I was able to make this work, sort of. There were several problems standing in my way. For one thing, it may be that using Ruby to process the piped-in stdin from another process doesn't work on Windows 2003R2. Another direction, suggested by Adrian below, was to run my script as the parent process and use popen to connect to myapp.exe as a forked child process. Unfortunately, fork isn't implemented in Windows, so this didn't work either.
Finally I was able to download POpen4, a RubyGem that does implement popen on Windows. Using this in combination with Adrian's suggestion, I was able to write this script which does what I really want -- processes the output from myapp.exe:
file: my_script.rb
require 'rubygems'
require 'popen4'
status =
POpen4::popen4("myapp.exe") do |stdout, stderr, stdin, pid|
puts pid
while s = stdout.gets
puts s
end
end
This script echoes the output from myapp.exe, which is exactly what I want.
Try just plain gets, without the $stdin. If that doesn't work, you might have to examine the output of myapp.exe for non-printable characters with another ruby script, using IO.popen.
gets doesn't always use stdin but instead tries to open a file.
See SO.
Try executing your Ruby script by explicitly calling ruby:
myapp.exe | ruby my_script.rb
I've experienced some odd behavior using stdin in Ruby when relying on Windows to invoke the correct program based on the file associations.

OSX Malicious Terminal Command (colon, brackets, curly brackets, apersand, etc) [duplicate]

This question already has answers here:
The Bash command :(){ :|:& };: will spawn processes to kernel death. Can you explain the syntax?
(4 answers)
Closed 8 years ago.
Ok, so someone "challenged" me to enter this into my OSX Terminal, but I have no idea what it would do:
WARNING to the reader: the following line can be harmful; do NOT enter it unless you know what you are doing:
:(){ :|:& };:
Any ideas?
It's a fork bomb. Don't do it. (Actually, as GB pointed out quickly, the copy here started out as a broken fork bomb. It was missing its final colon.) Still, if someone says, "Try this command" while snickering, and you don't know what it does, common sense says...
Edit: The one you have here is pretty famous as a work of art by Jaromil, a digital artist.
Breaking down the command so it's actually understandable:
:() #Define new function
#named ':'
{ #Begin function definition
#block
:|:& #Pipe the very ':' function through itself,
#creating two processes, and make the
#resulting copy run in the background
#(the & part)
} #End function definition block
;: #Call ':' for the first time, initiating a chain
#reaction: each instance of ':' will create two
#more instances, ad infinitum
Then again, from my experience Mac OS X happens to have a per-user limit for the number of processes one can execute, so unless you actually have the guts to run the fork bomb under a sudo -s or sudo -i shell, you should be fine.
It does nothing harmful, since Mac OS X has a (per-user) upper bound for number of processes.
Absolutely nothing. It's an incomplete version of the "fork bomb", missing a colon at the end.
Fork bomb!
I mean... fun bomb! Give it a try inside a virtual machine.
On properly configured systems it doesn't do much harm, you should be able to try it.

Resources