noizZze

Ruby: Executing Commands With Prompts

There are several ways to execute a shell command from your Ruby script. They give you the output and exit code which is often enough. But what if you need more than that? Recently I needed to run the command that prompted for a password. Here’s my simple solution to this – you give the command as usual and then a Hash of matchers-responses. Every line in STDOUT will be analyzed and if it matches any of these guys, the response will be sent to the STDIN. As simple as that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
require 'open3'

def system_with_prompt(cmd, responses = {})
  buffer = []

  Open3.popen3(cmd) do |stdin, stdout, stderr|
    while line = stdout.gets

      # Find the response
      responses.each do |k, v|
        match = case
        when k.is_a?(Regexp)
          k =~ line
        else
          k.to_s == line
        end

        # Respond if found
        if match
          v = v.call if v.is_a?(Proc)
          stdin.puts v.to_s
        end
      end

      buffer < < line
    end
  end

  buffer.join
end

# - you get your output as usual
# - you can feed many prompt-response pairs in hash
# - prompt matcher can either be a string or a regex
# - response can be either a string or a lambda / Proc returning the result
output = system_with_prompt("command_with_password arg1", /password:/i => lambda { Time.now.to_s }, 'Another Filed' => '...')
puts output