Launch subprocess in Ruby and continue execution of script - ruby

I want to launch a subprocess in Ruby, concretely an external .exe file (I'm working in Windows environment). I don't want to block the Ruby script, so I want to return to the next line of the script while the subprocess is running. The Ruby script can even finish before the subprocess is done.
Is there any way to do it? I've tried exec(), fork(), spawn(), system()... but cannot make it work properly.

You could use Thread:
Thread.new { <your logic here> }
There are a bunch of helper methods defined on Thread which will allow you to monitor and manipulate the thread.

Related

Python subprocess.Popen terminates when stdin=PIPE is specified

I'm new to subprocesses in python, I need to spawn a number of independent subprocesses, keep them alive and pass commands into them. At first sight, subprocess library is what I'm looking for.
I've read the documenations for it and as I'm understanding to pass any command into the subprocess, I'd have to specify the input.
I need to run commands via windows command line, hence the toy example below is good enough that if I have it working, I'm pretty much done. Running code below via IDLE opens a new cmd window, printing a list of cwd files, however I can't write to it as stdin is not specified (would be writing to it using p.stdin.write('DIR') with 'DIR' being an example command).
from subprocess import Popen, PIPE
p = Popen(['cmd', '/K', 'DIR'])
Therefore I specify the stdin as PIPE, as per documentations.
from subprocess import Popen, PIPE
p = Popen(['cmd', '/K', 'DIR'], stdin=PIPE)
However, running the second snippet of code instantly terminates the opened cmd window. Is that the expected behavior? As far as I could find in the documentations, only p.kill() or p.terminate() end the child process. If so, what are the possible workarounds? If not, what am I doing incorrectly, what other libraries should I be using? Thanks!

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.

Process.daemon vs. running a Ruby script with nohup + &

I have a Ruby 1.9 script that I want to run as a long-running background process.
It looks like I have a choice between calling Process.daemon inside the script to daemonize it, or I can just run the script in the background using a shell's ampersand and keep it running after I log out of the server by prefixing the command with nohup.
Which way is better?
Process.daemon seems like a more clean and straightforward way, especially if this is something you would ever way to turn into a full-fledged daemon that is started during boot.

Remotely manipulating the execution of a batch file

I have a batch file that is located on one machine that I am invoking remotely from another machine. That batch file is pretty simple; all it does is set some environment variables and then executes an application - the application creates a command window and executes inside of it. The application it executes will run forever unless someone types in the command window in which it is executing "quit", at which point it will do some final processing and will exit cleanly. If I just close the command window, the exit is not clean and that is bad for a number of different reasons related to the data that this application produces. Is there a way for me to perhaps write another batch script that will insert the "quit" command into the first command window and then exit?
I'd write a little script using the subprocess module in python, like so:
from subprocess import Popen, PIPE
import os
import os.path
import time
app = Popen(['c:/path/to/app.exe', 'arg1', 'arg2'], stdin=PIPE, env = {
'YOUR_ENV_VAR_1': 'value1',
'YOUR_ENV_VAR_2': 'value2',
# etc as needed to fill environment
})
while not os.path.exists('c:/temp/quit-app.tmp'):
time.sleep(60)
app.communicate('quit\n')
print "app return code is %s" % app.returncode
Then, you remotely invoke a batch script that creates c:/temp/quit-app.tmp when you want to shut down, wait a couple of minutes, and then deletes the file.
Naturally, you need Python installed on the Windows machine for this to work.
It sounds like the type of job for which I'd use expect, though I've never used it under Windows.
You could use the < to take the "quit" from a text file instead of the console... but that would quit your process as soon as it loads. Would that work?
Otherwise you could write a program to send keystrokes to the console... but I don't think this is a production quality trick.
Do you have access to the actual code of the application? if so you can check for a batch file. Else you can do something like the following using powershell.
$Process = Get-Process | Where-Object {$_.ProcessName -eq "notepad"}If (!($Process))
{ "Process isn't running, do stuff"
}Else
{ $myshell.AppActivate("notepad")
$myshell.sendkeys("Exit")
}
I am only suggesting powershell as its easy for you to call the code. you could also put in a loop and wait for it to run.
RE

Resources