1

I want to start an FTP process, issue commands, check for a specially formatted response strings and capture them, then issue commands based on the captured strings.

So the flow is:

  1. start ftp

  2. echo the welcome text

  3. for each ftp subcommand

    a) issue subcommand

    b) echo the response for the subcommand

    c) scan the response for a pattern and save the matches for later

  4. perform a computation on the saved patterns

  5. issue more ftp commands

  6. echo the response

Here is my script, which does not read ftp output and hangs after attempting to write the first ftp subcommand:

require 'io/wait'
require 'open3'

# Define the commands to send to FTP
commands = [
  'ascii',
  'quote site filetype=jes',
  'put amblist.jcl',
  'dir'
]

user_id = 'mikes01'.downcase
program_command = "ftp ftp://#{user_id}:mypwd@bigiron"
Open3.popen2(program_command) do |stdin, stdout, wait_thread|
  Thread.new do
    stdout.each do |line|
      # I want to scan the line for a pattern but we never get here
      puts line
      stdout.flush
    end
  end

  commands.each do |command| # Issue command
    stdin.puts command
    # Hopefully the output resulting from the ftp command is captured in the above thread
  end
  # Do something with previously processed output before closing the FTP session
  stdin.close
  wait_thread.value # exit status
end
# Do more processing
5
  • 1
    Remote controlling the ftp command line tool which provides a REPL seems quite complicated. Wouldn't it be easier to use Ruby's Net::FTP library to communicate with the FTP server directly?
    – Stefan
    Commented Apr 9 at 9:54
  • The remote server is a mainframe, using EBCDIC, not ASCII or UTF-8, and there are several complexities that I did not incorporate into the above code. When mainframes are involved, even the simplest task becomes a considerable effort. Best to leave the infrastructure in place and work with it.
    – Mike Slinn
    Commented Apr 9 at 18:29
  • I realized your suggestion would be the right way to go if the quote subcommand was implemented in Net::FTP, so I wrote it and created a pull request.
    – Mike Slinn
    Commented May 2 at 20:35
  • Nice! But does Ruby’s FTP library support type EBCDIC?
    – Stefan
    Commented May 3 at 5:32
  • No need, the IBM ftp server converts EBCDIC to ASCII, so the communication is done in ASCII.
    – Mike Slinn
    Commented May 4 at 12:53

1 Answer 1

0

My original approach was unworkable, so I followed the suggestion from @Stefan and looked into the Ruby Net::FTP gem. I modified the gem to include the necessary functionality, present in the Linux FTP command. I made a pull request.

The modifications in the pull request have been tested against an IBM z/OS Communications Server. The following code fragment uses FTP to submit a batch job to the mainframe, and collects the results.

def parse_job_number_from(line)
  tokens = line.split('JOB')
  raise StandardError, "Error: The string 'JOB' was not found in the FTP response." unless tokens.length == 2

  job_number = tokens[1].split.first
  job_number.sub(/^0+/, '') # Remove leading zeros
end
    
Net::FTP.open(@ip_or_domain) do |ftp|
  ftp.login @uid, @pwd
  ftp.quote 'site filetype=jes'
  job_info = ftp.puttextfile @local_jcl_filepath
  job_number = parse_job_number_from job_info
  ftp.gettextfile "J#{job_number}", @local_results_file
end

Not the answer you're looking for? Browse other questions tagged or ask your own question.