Проблема зомби. Да, действительно.
Все ядра Unix-стиля оставляют процесс, пока кто-то его не ждет. (Это для того, чтобы отслеживать PID, статус выхода и немного другого.) Они называются зомби и имеют Z-состояние в списке ps (1). Вы не можете убить их, потому что они уже мертвы. Они уходят, когда вы их ждете.
Итак, как очистить ваш @shell
объект:
@shell[0].close
@shell[1].close
begin
Process.wait @shell[2]
rescue PTY::ChildExited
end
Вам может не понадобиться спасательный блок в зависимости от того, есть ли у вас слои более высокого уровня, перехватывающие исключения слишком широко. (Вздох, как мой ирб.)
Кстати, причина, по которой ваш процесс, наконец, исчез при выходе из программы Ruby, заключается в том, что тогда зомби также стал сиротой (без родительского процесса) и либо оболочка, либо init (8) в конечном итоге будут ждать всех сирот. *