Scripting an External Program


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=\)
+) do |io|
	 io.puts input

	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

	 # 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

	 # The default value for the timeout is 9999999 seconds
	 read.expect("Retype new UNIX password:") do |response|
	 write.puts new_pwd + "
" if response

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.

See Also

  • Recipe 20.8, "Driving an External Process with popen"
  • Recipe 21.9, "Reading a Password," shows how to obtain a password without echoing it to the screen



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


Graphics and Other File Formats

Databases and Persistence

Internet Services

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

User Interface

Extending Ruby with Other Languages

System Administration

Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399 © 2008-2020.
If you may any questions please contact us: