Skip to content

Instantly share code, notes, and snippets.

@thinkerbot
Created August 28, 2011 04:24
Show Gist options
  • Save thinkerbot/1176245 to your computer and use it in GitHub Desktop.
Save thinkerbot/1176245 to your computer and use it in GitHub Desktop.
Example of a pseudo-terminal shell via PTY
require 'pty'
require 'expect'
def shellout(shell, *lines)
prompt = /^(?:#{Regexp.escape(ENV['PS1'])}|#{Regexp.escape(ENV['PS2'])})/
lines << 'exit'
PTY.spawn(shell) do |stdin,stdout,pid|
begin
lines.each do |line|
buffer, match = stdin.expect(prompt)
print(buffer || "\n")
stdout.puts line
end
rescue Errno::EIO
# the presence of this rescue indicates my not knowing how to detect
# that stdout can no longer accept inputs. I think that after the exit
# 2, the slave no longer is available, so while stdout is still open,
# there isn't anything to recieve the data and hence the error.
#
# the unfortunate symptom of this rescue is the prompt being printed one
# last time (since print buffer is ok before stdout fails)
end
print stdin.read
Process.wait(pid)
end
end
ENV['PS1'] = '$ '
ENV['PS2'] = '> '
# single command
shellout 'sh',
'echo a'
puts "status: #{$?.exitstatus}"
puts
# multiple commands + context
shellout 'sh',
'A="B"',
"echo a",
"echo $A"
puts "status: #{$?.exitstatus}"
puts
# multiline command, redirections
shellout 'sh',
"cat > stdout <<DOC",
"abc",
"xyz",
"DOC",
"cat stdout"
puts "status: #{$?.exitstatus}"
puts
# exit and flow control
shellout 'sh',
"if false",
"then exit 0",
"fi",
"if true",
"then exit 2",
"fi"
puts "status: #{$?.exitstatus}"
puts
# fancy output
shellout 'sh',
"ruby <<'SCRIPT'",
'print "?"; $stdout.flush; sleep 1',
'print "\r"; $stdout.flush',
'print "."; $stdout.flush',
"puts",
"SCRIPT"
puts "status: #{$?.exitstatus}"
puts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment