module Subprocess
A Ruby clone of Python's subprocess module.
Constants
- PIPE
An opaque constant that indicates that a pipe should be opened.
- STDOUT
An opaque constant that can be passed to the `:stderr` option that indicates that the standard error stream should be redirected to the standard output.
- VERSION
Public Class Methods
Call and wait for the return of a given process.
@note If you call this function with `:stdout => PIPE` or `:stderr => PIPE`,
this function will block indefinitely as soon as the OS's pipe buffer fills up, as neither file descriptor will be read from. To avoid this, use {Process#communicate} from a passed block.
@param [Array<String>] cmd See {Process#initialize} @param [Hash] opts See {Process#initialize} @yield [process] See {Process#initialize} @yieldparam process [Process] See {Process#initialize}
@return [::Process::Status] The exit status of the process
@see Process#initialize
# File lib/subprocess.rb, line 45 def self.call(cmd, opts={}, &blk) Process.new(cmd, opts, &blk).wait end
Like {Subprocess::call}, except raise a {NonZeroExit} if the process did not terminate successfully.
@example Grep a file for a string
Subprocess.check_call(%W{grep -q llama ~/favorite_animals})
@example Communicate with a child process
Subprocess.check_call(%W{sendmail -t}, :stdin => Subprocess::PIPE) do |p| p.communicate <<-EMAIL From: alpaca@example.com To: llama@example.com Subject: I am so fluffy. SO FLUFFY! http://upload.wikimedia.org/wikipedia/commons/3/3e/Unshorn_alpaca_grazing.jpg EMAIL end
@note If you call this function with `:stdout => PIPE` or `:stderr => PIPE`,
this function will block indefinitely as soon as the OS's pipe buffer fills up, as neither file descriptor will be read from. To avoid this, use {Process#communicate} from a passed block.
@param [Array<String>] cmd See {Process#initialize} @param [Hash] opts See {Process#initialize} @yield [process] See {Process#initialize} @yieldparam process [Process] See {Process#initialize}
@raise [NonZeroExit] if the process returned a non-zero exit status (i.e.,
was terminated with an error or was killed by a signal)
@return [::Process::Status] The exit status of the process
@see Process#initialize
# File lib/subprocess.rb, line 82 def self.check_call(cmd, opts={}, &blk) status = Process.new(cmd, opts, &blk).wait raise NonZeroExit.new(cmd, status) unless status.success? status end
Like {Subprocess::check_call}, but return the contents of `stdout`, much like {::Kernel#system}.
@example Get the system load
system_load = Subprocess.check_output(['uptime']).split(' ').last(3)
@param [Array<String>] cmd See {Process#initialize} @param [Hash] opts See {Process#initialize} @yield [process] See {Process#initialize} @yieldparam process [Process] See {Process#initialize}
@raise [NonZeroExit] if the process returned a non-zero exit status (i.e.,
was terminated with an error or was killed by a signal)
@return [String] The contents of `stdout`
@see Process#initialize
# File lib/subprocess.rb, line 104 def self.check_output(cmd, opts={}, &blk) opts[:stdout] = PIPE child = Process.new(cmd, opts, &blk) output, _ = child.communicate() raise NonZeroExit.new(cmd, child.status) unless child.wait.success? output end
An alias for `Process.new`. Mostly here to better emulate the Python API.
@param [Array<String>] cmd See {Process#initialize} @param [Hash] opts See {Process#initialize} @yield [process] See {Process#initialize} @yieldparam process [Process] See {Process#initialize} @return [Process] A process with the given arguments
@see Process#initialize
# File lib/subprocess.rb, line 26 def self.popen(cmd, opts={}, &blk) Process.new(cmd, opts, &blk) end
Print a human readable interpretation of a process exit status.
@param [::Process::Status] status The status returned by `waitpid2`. @param [Boolean] convert_high_exit Whether to convert exit statuses greater
than 128 into the usual convention for exiting after trapping a signal. (e.g. many programs will exit with status 130 after receiving a SIGINT / signal 2.)
@return [String] Text interpretation
# File lib/subprocess.rb, line 121 def self.status_to_s(status, convert_high_exit=true) # use an array just in case we somehow get a status with all the bits set parts = [] if status.exited? parts << "exited with status #{status.exitstatus}" if convert_high_exit && status.exitstatus > 128 # convert high exit statuses into what the original signal may have # been according to the usual exit status convention sig_num = status.exitstatus - 128 sig_name = Signal.signame(sig_num) if sig_name parts << "(maybe SIG#{sig_name})" end end end if status.signaled? parts << "killed by signal #{status.termsig}" end if status.stopped? parts << "stopped by signal #{status.stopsig}" end if parts.empty? raise ArgumentError.new("Don't know how to interpret #{status.inspect}") end parts.join(', ') end