You want to automatically control an external program that expects to get terminal input from a human user.
When you e running a program that only needs a single string of input, you can use IO.popen, as described in Recipe 20.8. This method runs a command, sends it a string as standard input, and returns the contents of its standard output:
def run(command, input=\) IO.popen(command, +) do |io| io.puts input io.close_write return io.read end end run wc -w, How many words are in this string? # => "7 "
This technique is commonly used to invoke a command with sudo, which expects the users password on standard input. This code obtains a users password and runs a command on his behalf using sudo:
print Enter your password for sudo: sudo_password = gets.chomp run(sudo apachectl graceful, user_password)
IO.popen is a good way to run noninteractive commandscommands that read all their standard input at once and produce some output. But some programs are interactive; they send prompts to standard output, and expect a human on the other end to respond with more input.
On Unix, you can use Rubys standard PTY and expect libraries to spawn a command and impersonate a human on the other end. This code scripts the Unix passwd command:
require expect require pty print Old password: old_pwd = gets.chomp print " New password:" new_pwd = gets.chomp PTY.spawn(passwd) do |read,write,pid| write.sync = true $expect_verbose = false # If 30 seconds pass and the expected text is not found, the # response object will be nil. read.expect("(current) UNIX password:", 30) do |response| write.print old_pwd + " " if response end # You can use regular expressions instead of strings. The code block # will give you the regex matches. read.expect(/UNIX password: /, 2) do |response, *matches| write.print new_pwd + " " if response end # The default value for the timeout is 9999999 seconds read.expect("Retype new UNIX password:") do |response| write.puts new_pwd + " " if response end end
The read and write objects in the PTY#spawn block are IO objects. The expect library defines the IO#expect method found throughout this example.
Date and Time
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
Extending Ruby with Other Languages