Create a Ruby Pseudo Terminal (PTY) and Invoke an Interactive Command (SFTP)

| Comments

Purpose

I needed to upload files on a SFTP server programmatically and automatically in a RoR Enviroment. SFTP ruby library wrapper are very limited (I only found this one actually) and is in maintenance (not more maintained) and I had some troubles uploading large files.

Anyway I decided to come back to use the old SFTP Command Line Interface who is perfectly working.

Unlucky this one is an Interactive CLI.

The trick is to use a Ruby Pseudo Terminal (PTY), listen to the console input for some patterns and write in the console output according this pattern as a real user would do.

Here is a code snippet who doing the job and working perfectly.

Code

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
38
39
40
41
42
require 'pty'
require 'expect'

PTY.spawn('sftp [email protected]:/uploads') do |input, output|

  # Say yes to SSH fingerprint
  input.expect(/fingerprint/, 2) do |r|

    output.puts "yes" if !r.nil?

    # Enter SFTP password
    input.expect(/password/, 2) do |r|

      output.puts 'your_sftp_password' if !r.nil?

      input.expect(/sftp/) do

        # List folders and files in `/uploads`
        output.puts 'ls'

        # Check if folder named `foo` exist
        input.expect(/foo/, 1) do |result|

          is_folder_exist = result.nil? ? false : true
          # Create `foo` folder if does'nt exist
          output.puts "mkdir foo" if !is_folder_exist
          # Change directory to `foo`
          output.puts "cd foo"
          # Upload `/path/to/local/foo.txt` in `foo` folder as `foo.txt`
          output.puts "put /path/to/local/foo.txt foo.txt"
          # Exit SFTP
          output.puts "exit"

        end

      end

    end

  end

end

Gist

Available here. Please feel free to improve it !

More…