How to run code after ruby Kernel.exec
You cannot.
Per the documentation for Kernel#exec
, "[it] replaces the current process by running the given external command". That means that you are no longer running your code but instead the code you specified by the command.
If you want to "wrap" a system call then you should use Kernel#system
(or the backtick operator) to execute the command in a subshell.
Run a command in current terminal in ruby then execute code when it exits
Thanks a lot to hek2mgl for pointing in the right direction:
include Signal
include Process
# Handling SIGINT by doing nothing prevents default behaviour
# (killing both processes)
Signal.trap("INT") {}
# Fork off subprocess (so exec won't exit from your main process)
pid = fork
if pid == nil then
# Child code. Use exec(!) to avoid the signal handler
# getting called in the child.
exec 'heroku run console'
else
# Wait for subprocess to exit
wait pid
# "wait" sets the $? according to the subprocess exit status
exit_status = $?.exitstatus
p "Execute more ruby code"
exit exit_status
end
why ruby code crash/exit after my second exec call?
Kernel#exec
replaces the current running process. Once it's executed, the remaining part of the code is not run.
puts "start"
ret1 = exec('pwd') # <---- After this, no more remaining code is executed.
...
If you want to get the output of the command, use Kernel#`
instead:
puts "start"
ret1 = `pwd`
ruby backtick, kernel.system, exec , command does not succeed
Turns out the issue was I was not closing the files I was creating.
Apparently that was fine when I was invoking it directly from the shell or directly from .sh, because the ruby script had already exited.
However when I would invoke this from the Ruby script it would not be able to access the file and would create issues.
Bottom line: Close your files else loose half day of work !
Ruby - Using Kernel.exec with custom STDOUT
What gets preserved in the other process is the underlying file descriptor (or rather they are hooked up under the hood), so as I commented I don't think you'll ever get writes to that descriptor to be funnelled through your write method - exec
replaces the running process with a new one.
A possible approach is to create a pipe, pass one end to your child process and then read from the other end, inserting prefixes as needed,
For example you might do
IO.pipe do |read_pipe, write_pipe|
fork do
exec("echo hello", out: write_pipe)
end
write_pipe.close
while line = read_pipe.gets
puts "prefix: #{line}"
end
end
You might also be interested in IO.popen
which wraps some of this up.
How to call shell commands from Ruby
This explanation is based on a commented Ruby script from a friend of mine. If you want to improve the script, feel free to update it at the link.
First, note that when Ruby calls out to a shell, it typically calls /bin/sh
, not Bash. Some Bash syntax is not supported by /bin/sh
on all systems.
Here are ways to execute a shell script:
cmd = "echo 'hi'" # Sample string that can be used
Kernel#`
, commonly called backticks –`cmd`
This is like many other languages, including Bash, PHP, and Perl.
Returns the result (i.e. standard output) of the shell command.
Docs: http://ruby-doc.org/core/Kernel.html#method-i-60
value = `echo 'hi'`
value = `#{cmd}`Built-in syntax,
%x( cmd )
Following the
x
character is a delimiter, which can be any character.
If the delimiter is one of the characters(
,[
,{
, or<
,
the literal consists of the characters up to the matching closing delimiter,
taking account of nested delimiter pairs. For all other delimiters, the
literal comprises the characters up to the next occurrence of the
delimiter character. String interpolation#{ ... }
is allowed.Returns the result (i.e. standard output) of the shell command, just like the backticks.
Docs: https://docs.ruby-lang.org/en/master/syntax/literals_rdoc.html#label-Percent+Strings
value = %x( echo 'hi' )
value = %x[ #{cmd} ]Kernel#system
Executes the given command in a subshell.
Returns
true
if the command was found and run successfully,false
otherwise.Docs: http://ruby-doc.org/core/Kernel.html#method-i-system
wasGood = system( "echo 'hi'" )
wasGood = system( cmd )Kernel#exec
Replaces the current process by running the given external command.
Returns none, the current process is replaced and never continues.
Docs: http://ruby-doc.org/core/Kernel.html#method-i-exec
exec( "echo 'hi'" )
exec( cmd ) # Note: this will never be reached because of the line above
Here's some extra advice:$?
, which is the same as $CHILD_STATUS
, accesses the status of the last system executed command if you use the backticks, system()
or %x{}
.
You can then access the exitstatus
and pid
properties:
$?.exitstatus
For more reading see:
- http://www.elctech.com/blog/i-m-in-ur-commandline-executin-ma-commands
- http://blog.jayfields.com/2006/06/ruby-kernel-system-exec-and-x.html
- http://tech.natemurray.com/2007/03/ruby-shell-commands.html
Getting output of system() calls in Ruby
I'd like to expand & clarify chaos's answer a bit.
If you surround your command with backticks, then you don't need to (explicitly) call system() at all. The backticks execute the command and return the output as a string. You can then assign the value to a variable like so:
output = `ls`
p output
or
printf output # escapes newline chars
Restart ruby program
Just run Kernel.exec
function that will replace running process with the new one.
The advantage of exec
function is that there's no time span when two different bots are run simultaneously. It was one process and after exec
call it's instantly replaced with the new one.
Run a shell script from ruby
You can do this a few different ways
Kernel.system "command"
%x[command]
`command`
Related Topics
I Want to Return a Single Result Using .Find() with Ruby on Rails
How to Sort a Ruby Array by Two Conditions
Does Ruby Provide a Constant_Added Hook Method
Why Rails Instance Method Can Be Used as Class Method in Rspec
Duplicate Elements of Array in Ruby
Error Loading the 'Sqlite3' Active Record Adapter. When I Deploy in Heroku
How to Condense Summable Metrics to a Unique Identifier in a Ruby Table
How to Use 'Debugger' and 'Pry' When Developing a Gem? (Ruby)
Selenium Webdriver Take Screenshot of Viewport Only
Why Must I Explicitly Call Self on Accessor When Using the Array Union Operator |= in Ruby
Implementing Dry-Run in Ruby Script
Rails Activerecord: Saving Nested Models Is Rolled Back
Ruby/Rails - Active Record Db Migration to MySQL - Timestamp Type
Can't Find Ffi.H When Installing Ffi Ruby Gem