title: Golang Correctly Handle Stdout of SSH Session
body: <p>I am writing a Go program to connect to a Cisco wireless controller to run multiple configuration commands on connected access points. I am able to connect to and send commands to the controller via Go's SSH package <code>golang.com/x/crypto/ssh</code>.</p>
  
  <p>I need to <strong>a)</strong> only print the output of each command I send, not the controller's prompt or login prompts, and <strong>b)</strong> figure out how to send successive commands after a command whose output includes <code>--More-- or (q)uit</code> prompts.</p>
  
  <p>Right now I have the <code>os.Stdout</code> assigned to the SSH <code>session.Stdout</code>, which is why I'm printing more than just the output of the commands I send. How would I  manually control the output of <code>session.Stdout</code>? I know the <code>session.Stdout</code> is an <code>io.Writer</code>, but I don't know how to control what it writes to <code>os.Stdout</code>. Here is my code along with its output:</p>
  
  <pre><code>package main
  
  import (
      "bufio"
      "fmt"
      "golang.org/x/crypto/ssh"
      "golang.org/x/crypto/ssh/terminal"
      "log"
      "os"
      "time"
      "io"
  )
  
  func SendCommand(in io.WriteCloser, cmd string) error {
      if _, err := in.Write([]byte(cmd + "\n")); err != nil {
          return err
      }
  
      return nil
  }
  
  func main() {
      // Prompt for Username
      fmt.Print("Username: ")
      r := bufio.NewReader(os.Stdin)
      username, err := r.ReadString('\n')
      if err != nil {
          log.Fatal(err)
      }
  
      // Prompt for password
      fmt.Print("Password: ")
      password, err := terminal.ReadPassword(int(os.Stdin.Fd()))
      if err != nil {
          log.Fatal(err)
      }
  
      // Setup configuration for SSH client
      config := &amp;ssh.ClientConfig{
          Timeout: time.Second * 5,
          User:    username,
          Auth: []ssh.AuthMethod{
              ssh.Password(string(password)),
          },
          HostKeyCallback: ssh.InsecureIgnoreHostKey(),
      }
  
      // Connect to the client
      client, err := ssh.Dial("tcp", "host:22", config)
      if err != nil {
          log.Fatal(err)
      }
      defer client.Close()
  
      // Create a session
      session, err := client.NewSession()
      if err != nil {
          log.Fatal(err)
      }
      defer session.Close()
  
      // Setup StdinPipe to send commands
      stdin, err := session.StdinPipe()
      if err != nil {
          log.Fatal(err)
      }
      defer stdin.Close()
  
      // Route session Stdout/Stderr to system Stdout/Stderr
      session.Stdout = os.Stdout
      session.Stderr = os.Stderr
  
      // Start a shell
      if err := session.Shell(); err != nil {
          log.Fatal(err)
      }
  
      // Send username
      if _, err := stdin.Write([]byte(username)); err != nil {
          log.Fatal(err)
      }
      // Send password
      SendCommand(stdin, string(password))
  
      // Run configuration commands
      SendCommand(stdin, "show ap summary")
      SendCommand(stdin, "logout")
      SendCommand(stdin, "N")
  
      session.Wait()
  }
  </code></pre>
  
  <p>Sample run:</p>
  
  <pre><code>$ go run main.go 
  Username: username
  Password: 
  
  (Cisco Controller) 
  User: username
  Password:****************
  (Cisco Controller) &gt;show ap summary
  
  Number of APs.................................... 1
  
  Global AP User Name.............................. its-wap
  Global AP Dot1x User Name........................ Not Configured
  
  AP Name             Slots  AP Model              Ethernet MAC       Location          Country     IP Address       Clients   DSE Location  
  ------------------  -----  --------------------  -----------------  ----------------  ----------  ---------------  --------  --------------
  csc-ap3500   2     AIR-CAP3502I-A-K9     00:00:00:00:00:00  csc-TESTLAB-ap35  US          10.10.110.10       0       [0 ,0 ,0 ]
  
  (Cisco Controller) &gt;logout
  The system has unsaved changes.
  Would you like to save them now? (y/N) N
  </code></pre>
  
  <p>My next problem comes when the output of a command has one or more <code>--More-- or (q)uit</code> prompts and I try to send a successive command. For example, here is the output of my code when running <code>show sysinfo</code> followed by <code>logout</code>:</p>
  
  <pre><code>$ go run main.go 
  Username: username
  Password: 
  
  (Cisco Controller) 
  User: username
  Password:****************
  (Cisco Controller) &gt;show sysinfo
  
  Manufacturer's Name.............................. Cisco Systems Inc.
  Product Name..................................... Cisco Controller
  Product Version.................................. 8.2.161.0
  Bootloader Version............................... 1.0.20
  Field Recovery Image Version..................... 7.6.101.1
  Firmware Version................................. PIC 16.0
  
  
  Build Type....................................... DATA + WPS
  
  --More-- or (q)uit
  
  Configured Country............................... US  - United States
  Operating Environment............................ Commercial (0 to 40 C)
  Internal Temp Alarm Limits....................... 0 to 65 C
  Internal Temperature............................. +23 C
  External Temperature............................. +28 C
  Fan Status....................................... 3900 rpm
  # the "l" is missing in "logout"
  (Cisco Controller) &gt;ogout
  
  Incorrect usage.  Use the '?' or &lt;TAB&gt; key to list commands.
  
  (Cisco Controller) &gt;N
  
  Incorrect usage.  Use the '?' or &lt;TAB&gt; key to list commands.
  # the program hangs here
  (Cisco Controller) &gt; 
  </code></pre>
  
  <p><strong>TL;DR</strong> How to manually control the output of an <code>io.Writer</code> and how to correctly handle sending commands in succession?</p>
  
  <p>Any help is appreciated. Thanks in advance.</p>