hello,
for fun, i am trying to use PTY to wrap my shell. i adapted script.rb
from ext/pty and can run and exit my shell okay, but i’m having trouble
getting the signals to work correctly. i can start up the shell, run
ps and vi, and do some basic shell comands, but i can’t interrupt or
suspend any jobs started by the shell.
when i call PTY.spawn, it gives me the pid of my shell. i put a trap
call in my ruby code to grab sigint and sigstop and send those onto the
shell’s pid, but i’m pretty sure i need to send those signals to
whatever subprocess my shell is currently running.
i’ve already written a class that parses ps output and lets me query the
process stack, but it’s pretty heavy and i’d rather not use it unless i
have to. i’m hoping that there is a cleaner way to do this in pure
ruby, parsing ps or /proc feels like i’m using too much brute force. i
like how short the current code is, so is there a ruby way to route the
signal properly?
if you’re wondering why i’m doing this, i thought it would be fun to
create a ruby program that runs a shell and lets you filter the input
and output of the shell with ruby plugins. when you hit enter after
entering a command on the prompt, your command is compared and if it
matches any plugins, they are ran instead of the command being passed to
the shell. i don’t know if it’s possible but it sounded like it would
be fun to experiment with…
thank you,
doug
p.s. i’m running ruby-1.8.0-preview2 compiled on os x 10.2.
#!/usr/bin/env ruby
require ‘pty’
input, output, pid = nil, nil, nil
shell = ENV[‘SHELL’]
if shell =~ /[^\w/.]/ || !File.stat(shell).executable?
raise "ENV[SHELL] must be a valid shell path!"
exit 1 # never reached
end
sending the signal to the shell doesn’t do it, i need to send the
signal to the process the shell is currently running. not sure
how to do that…
%w/INT STOP/.each do |signal|
trap(signal) do
if pid
kill(signal, pid)
end
end
end
begin
system "stty -echo raw lnext ^_"
input, output, pid = PTY.spawn(shell)
puts "input, output, pid = #{input}, #{output}, #{pid}"
Thread.new do
while true
output.print STDIN.getc.chr
output.flush
end
end
begin
while true
c = input.sysread(512)
break if c.nil?
print c
STDOUT.flush
end
rescue
end
rescue
STDERR.puts "general pty exception: #{$!}"
ensure
sometimes first stty call fails, don’t know why…
system(“stty echo -raw lnext ^v”) || system(“stty -raw”)
input.close
output.close
Process.kill(0, pid) && Process.kill(9, pid)
end
···
–
“Contrary to what most people say, the most dangerous animal in the
world is not the lion or the tiger or even the elephant. It’s a shark
riding on an elephant’s back, just trampling and eating everything they
see.” – Jack Handey