SHExecutor
SHExecutor is a convenience wrapper for executing shell commands from with-in a ruby process.
It supports:
- blocking indefinitely, on exit you can get status, stdout and stderr
- blocking with timeout, on exit you can get status, stdout, stderr, timeout exception (then output streams are not available)
- non-blocking, then you get handles to the output streams and the status of the forked process
- replacement, then you get a replaced process and none of the above
- redirecting of stderr and stdout, separately, to file, with the option to overwrite or append
It does not support:
- streaming input to stdin
For any executor:
- you can ask status, which will tell you "not executed", current status (e.g. run or sleep) and "no longer executing"
- you can ask result, which gives you nil unless the process is no longer executing, in which case you get status (e.g. pid, exit code, sigints.)
For a full description of status, please see Process::Status
This gem is sponsored by Hetzner (Pty) Ltd - http://hetzner.co.za
Initialization options:
Required / optional:
{
:application_path # Path of the command to run
:params # Parameters to pass the command
}
@@default_options = {
:timeout => -1, # Seconds after which to raise Timeout::Error if not completed
:protect_against_injection => true, # look for spaces in and tainted application path
:stdout_path => nil, # file to append stdout to
:stderr_path => nil, # file to append stderr to
:append_stdout_path => true, # if true, will append, otherwise will overwrite
:append_stderr_path => true, # if true, will append, otherwise will overwrite
:replace => false, # replace the running process with the command
:wait_for_completion => false, # block until the command completes
:timeout_sig_kill_retry => 500 # if timeout occurs, send TERM, and send signal 9 if still present after X ms
}
Installation
Add this line to your application's Gemfile:
gem 'shexecutor'
And then execute:
$ bundle
Or install it yourself as:
$ gem install shexecutor
Module helpers
Blocking
result, stdout, stderr = ::SHExecutor::execute_blocking("/bin/ls", "/tmp/")
Blocking with timeout
result, stdout, stderr = ::SHExecutor::execute_and_timeout_after("/bin/sleep", "10", 2)
Non-blocking
thr, stdout_io, stderr_io = ::SHExecutor::execute_non_blocking("/bin/sleep", "20")
Executor API
Blocking
iut = SHExecutor::Executor.new({:wait_for_completion => true, :application_path => "/bin/echo", :params => ["hello world"]})
result = iut.execute
iut.flush
puts "After execution status is: #{iut.status}"
# "no longer executing"
puts "out: #{iut.stdout} err: #{iut.stderr}"
puts "#{result.pid} success? #{result.success?} with code #{result.exitstatus}"
puts "For more see: #{iut.result.methods}"
Blocking with timeout
iut = SHExecutor::Executor.new({:timeout => 1, :wait_for_completion => true, :application_path => "/bin/sleep", :params => ["2"]})
result = iut.execute
# Timeout::Error gets raised. The spawned process is killed with TERM, and then with signal 9 if it does not close in timeout_sig_kill_retry ms
Non-blocking
iut = SHExecutor::Executor.new({:wait_for_completion => false, :application_path => "/bin/sleep", :params => ["1"]})
stdout, stderr, thr = iut.execute
puts "Status: #{iut.status}"
puts "PID: #{thr.pid}"
# "run" or "sleep"
sleep 2
puts "Status: #{iut.status}"
# "no longer executing"
Replacing
iut = SHExecutor::Executor.new({:replace => true, :application_path => "/bin/echo", :params => ["Your process has been assimilated"]})
iut.execute
stdout and stderr
iut.flush
puts iut.stdout
puts iut.stderr
redirecting stdout and stderr
iut = SHExecutor::Executor.new({:wait_for_completion => true, :application_path => "/bin/echo", :params => ["this is stdoutin a file"], :stdout_path => "/tmp/mystdout", :stderr_path => "/tmp/mystderr", :append_stdout_path => false, :append_stderr_path => true})
iut.execute
iut.flush
puts iut.stdout
puts iut.stderr
Remember to call iut.flush in order to stream stdout and stderr to the Executor object.
Note: calling flush will block if execute was called non-blocking, so wait until the execute has finished to preserve non-blocking behaviour.
Please send feedback and comments to the author at:
Ernst van Graan [email protected]
Contributing
- Fork it ( https://github.com/[my-github-username]/executor/fork )
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request