Выход из ruby ​​в подоболочке без убийства родителя

У меня есть программа Ruby A, которая вызывает программу Ruby B с помощью:

 system("ruby programB.rb <parameters>")

При определенных условиях я хочу, чтобы программа B завершила свою работу (и связанную с ней подоболочку), но позволила программе A перейти к следующему набору параметров.

Однако exit() и abort() убивают как подоболочку, так и родителя, и я не могу заставить Process.kill("SIGTERM",0) работать в программе B (к сожалению, это в Windows). У меня рубин 1.9.2.

Как я могу завершить программу B, не убивая при этом программу A?


person JESii    schedule 22.12.2012    source источник


Ответы (3)


Если обычный вызов system не работает, обычно можно сделать что-то вроде этого:

pid = fork do
  exec("ruby programB.rb ...")
end

kill("SIGTERM", pid)

Операция fork дает вам идентификатор процесса, который вы можете убить. system будет блокироваться до тех пор, пока дочерний процесс не вернется, поэтому любой вызов kill в родительском процессе повлияет только на родительский процесс.

К сожалению, в Windows нет fork, но есть альтернативы, которые достигают того же результата. .

person tadman    schedule 22.12.2012
comment
Спасибо за указание на альтернативы для Windows; Я сделал пометку на будущее. - person JESii; 22.12.2012

exit() и abort() не убивают родителя, по крайней мере, не в Mac OS и Linux, по моему опыту.

Попробуйте сохранить это как abort.rb:

puts RUBY_VERSION
puts `date`
puts 'aborting'
abort

а это как exit.rb:

puts RUBY_VERSION
puts `date`
puts 'exiting'
exit

Затем сохраните это как test.rb в том же каталоге и запустите:

puts `ruby exit.rb`
puts `ruby abort.rb`

В моей системе я вижу:

1.9.3
Fri Dec 21 22:17:12 MST 2012
exiting
1.9.3
Fri Dec 21 22:17:12 MST 2012
aborting

Они завершают текущий запущенный скрипт в подоболочке, которая затем завершается, потому что это не оболочка для входа в систему, и может установить статус возврата, который важен для вызывающей программы, но я еще не видел, чтобы они убивали родителя.

Если вам нужно захватить STDERR, использование обратных кавычек или %x не сработает. Я бы рекомендовал использовать Open3.capture3 для простоты, если вам нужно знать, какой код состояния был возвращен, или возвращал ли STDERR что-либо.

person the Tin Man    schedule 22.12.2012
comment
К вашему сведению, мне нужно было date /t для Windows, но в остальном он работал так, как вы ожидали, поэтому я вернулся, чтобы еще раз просмотреть свой код. Наконец нашел опечатку '\' вместо '|' что решило проблему. Спасибо! - person JESii; 22.12.2012

Единственное, что надежно работает для меня, это:

kill -INT $$

Он надежно убивает скрипт и только скрипт, даже если он был получен из командной строки. Обратите внимание, что я использую GNU bash версии 4.4.12(1)-выпуск (x86_64-apple-darwin15.6.0); Я не могу вспомнить, работает ли это на bash 3.x

person JESii    schedule 30.05.2017