在ruby中的当前终端中运行命令,然后在退出时执行代码

时间:2015-01-30 14:50:14

标签: ruby shell unix

我需要的是:

  1. 在调用系统命令之前执行某些操作。

  2. 执行我的系统命令

    1. 涉及提示和获取用户的答案

    2. 保持ctrl-c对被叫命令的影响不变

  3. 获取我的系统命令的结果并继续执行更多ruby代码

  4. 到目前为止,我尝试了类似的内容:

    #!/usr/bin/env ruby
    p "Foo"
    exit_value = exec 'heroku run console'
    p "Bar"
    exit exit_value
    

    这个失败是因为exec替换并终止了当前进程,因此在exec之后不再执行ruby代码

    我已经阅读过这篇文章了: How to run code after ruby Kernel.exec

    我尝试使用内核#system调用:

    #!/usr/bin/env ruby
    p "Foo"
    system 'heroku run console'
    p "Bar"
    exit $?
    

    这个也失败了,因为ctrl-c显然被我的ruby进程捕获并杀死它而不是达到它预期的目标。

    那么,有没有办法处理这些特殊要求?

2 个答案:

答案 0 :(得分:1)

非常感谢hek2mgl指向正确的方向:

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

答案 1 :(得分:0)

我会为SIGINT安装一个信号陷阱,分离子进程,执行命令(以防止信号处理程序在父进程和子进程中运行)并在发生SIGINT时终止子进程:

include Signal
include Process

# Define a signal handler for SIGINT
Signal.trap("INT") do
    if $pid != nil then
        # Kill the subprocess
        Process.kill("INT", $pid)
    else
        # Terminate ourself
        exit 1 
    end
end

# Fork off subprocess
# The $ marks the variable as global
$pid = fork
if $pid == nil then
    # Child code. Use exec(!) to avoid the signal handler 
    # getting called in the child.
    exec 'bash -c "echo test; sleep 3; echo test"'
end

# Wait for subprocess to exit
wait $pid
# Reset $pid
$pid = nil
exit_status = $?.exitstatus

# Detect whether the child process has been killed
if exit_status == nil then
    p "Child process has been killed."
end

p "Execute more ruby code"
...