Google


   


You are here: CodeIdol.com > Other > Ruby Cookbook > System Administration > Scripting An External Program

SAVE
Digg
Shown on del.icio.us del.icio.us
See Whos Talking About This on Technorati Technorati
I've Reddit reddit

Recipe 23.1. Scripting an External Program

Problem

You want to automatically control an external program that expects to get terminal input from a human user.

Solution

When you're 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, 'r+') do |io|
	    io.puts input
	    io.close_write
	    return io.read
	   end
	end

	run 'wc -w', 'How many words are in this string?'      # => "7\n"

This technique is commonly used to invoke a command with sudo, which expects the user's password on standard input. This code obtains a user's 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)

Discussion

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 Ruby's 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 "\nNew 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 + "\n" 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 + "\n" if response
	  end

	  # The default value for the timeout is 9999999 seconds
	  read.expect("Retype new UNIX password:") do |response|
	    write.puts new_pwd + "\n" 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.

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


SAVE
Digg
Shown on del.icio.us del.icio.us
See Whos Talking About This on Technorati Technorati
I've Reddit reddit

You are here: CodeIdol.com > Other > Ruby Cookbook > System Administration > Scripting An External Program


ADBRITE ads links
   
Related tags







Popular Categories
Unix books and guides

AJAX popular information
C# language guides
Windows books and cookbooks

.......








Business Key Top Sites

be number one
rate your site




    С 2009 года мы стали переводить структура сайта на различные языки. Сайт теперь будет содержать книги не только на английском языке, но также и на других европейских языках, в том числе и на Русском языке.

    Русский Polski Francais Deutsch
    support sitemap terms

© CodeIdol Labs, 2007 - 2009