Quick and Simple Executor of Bash Commands
How do you execute a new shell command from Ruby? There are many ways. None of them offers a one-liner that would execute a command, print its output to the console or a logger, and then raise an exception if the exit code is not zero. This small gem offers exactly this one-liner.
First, install it:
gem install qbash
Then, you can use qbash global function:
require 'qbash'
stdout = qbash('echo "Hello, world!"', log: $stdout)
If the command fails, an exception is raised.
The function automatically merges stderr with stdout
(you can't change this).
It's possible to provide the standard input and environment variables:
stdout = qbash('cat > $FILE', env: { 'FILE' => 'a.txt' }, stdin: 'Hello!')
It's possible to configure the logging facility too, for example, with the help of the loog gem (the output is returned and printed to the logger):
require 'loog'
qbash('echo "Hello, world!"', log: Loog::VERBOSE)
You can also make it return both stdout and exit code,
with the help of the both option set to true:
stdout, code = qbash('cat a.txt', both: true, accept: [])
Here, the accept param contains the list of exit codes that are "acceptable"
and won't lead to runtime failures.
When the list is empty, all exits are acceptable (no failures occur).
The command may be provided as an array, which is automatically converted to a string by joining all items with spaces between them.
qbash(
[
'echo "Hello, world!"',
'&& echo "How are you?"',
'&& cat /etc/passwd'
]
)
Even simpler:
qbash(
'echo "Hello, world!"',
'&& echo "How are you?"',
'&& cat /etc/passwd'
)
If a block is given to qbash, it runs the command in background mode,
waiting for the block to finish.
Once finished, the command is terminated via the TERM signal:
qbash('sleep 9999') do |pid|
# do something
end
It is very much recommended to escape all command-line values with the help of the Shellwords.escape() utility method, for example:
file = '/tmp/test.txt'
qbash("cat #{Shellwords.escape(file)}")
Without such escaping, a space inside the file variable
leads to an unpredictable result.
If you want to stop sooner than the command finishes, use timeout gem:
require 'timeout'
Timeout.timeout(5) do
qbash('sleep 100')
end
This raises a Timeout::Error exception after five seconds
of waiting for sleep to finish.
How to contribute
Read these guidelines. Make sure your build is green before you contribute your pull request. You need Ruby 3.0+ and Bundler installed. Then:
bundle update
bundle exec rake
If it's clean and you don't see any error messages, submit your pull request.