Sample code for 30+ languages & platforms
DataFlex

SSH Remote Shell with Multiple Commands

See more SSH Examples

Demonstrates running several commands one after another in a single remote shell session, retrieving each command's output separately. No PTY is requested, so each command is followed by an echoed marker that signals where its output ends.

Background: Interleaving commands and reads in one shell requires a way to know where each command's output stops. An interactive session would use the shell prompt, but without a PTY the shell is non-interactive and never prints one — so the dependable technique is to append echo SOME_MARKER to each command and read up to that marker. Retrieving the text also clears the receive buffer, which matters here: if a marker were left buffered, the next receive would match it immediately and return the wrong output.

Chilkat DataFlex Downloads

DataFlex
Use ChilkatAx-win32.pkg

Procedure Test
    Boolean iSuccess
    Handle hoSsh
    String sHostname
    Integer iPort
    String sPassword
    Integer iChannelNum
    Boolean iCaseSensitive
    String sCmdOutput
    String sTemp1
    Boolean bTemp1

    Move False To iSuccess

    //  This example requires the Chilkat API to have been previously unlocked.
    //  See Global Unlock Sample for sample code.

    //  Demonstrates running several commands one after another in a single remote shell session,
    //  retrieving each command's output separately.
    //  
    //  No PTY is requested, so the shell runs non-interactively and never prints a command prompt.
    //  Because there is no prompt to synchronize on, each command is followed by an "echo" of a
    //  unique marker, and the output is read up to that marker.

    Get Create (RefClass(cComChilkatSsh)) To hoSsh
    If (Not(IsComObjectCreated(hoSsh))) Begin
        Send CreateComObject of hoSsh
    End

    Move "ssh.example.com" To sHostname
    Move 22 To iPort
    Get ComConnect Of hoSsh sHostname iPort To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    //  Normally you would not hard-code the password in source.  You should instead obtain it
    //  from an interactive prompt, environment variable, or a secrets vault.
    Move "mySshPassword" To sPassword

    Get ComAuthenticatePw Of hoSsh "mySshLogin" sPassword To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComOpenSessionChannel Of hoSsh To iChannelNum
    If (iChannelNum < 0) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    //  Start a shell WITHOUT requesting a PTY.  Without a PTY the shell sees it is connected to a
    //  raw data pipe and enters non-interactive mode: it suppresses the command prompt, does not
    //  echo typed commands back, and skips interactive login scripts.  The output is therefore
    //  clean and easily parseable -- but because no prompt is ever sent, code must not wait for
    //  one.  Instead, have each command print a predictable marker, or wait for EOF / channel close.
    Get ComSendReqShell Of hoSsh iChannelNum To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    //  IMPORTANT: Set a read timeout before receiving until a match.  ReadTimeoutMs defaults to 0,
    //  which means no limit -- without it, this call waits forever if the received data never
    //  contains a match.
    Set ComReadTimeoutMs Of hoSsh To 15000

    Move True To iCaseSensitive

    //  ---- 1st command: change directory ----
    Get ComChannelSendString Of hoSsh iChannelNum "cd /tmp; echo END_OF_CMD_1" + (character(10)) "utf-8" To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComChannelReceiveUntilMatch Of hoSsh iChannelNum "END_OF_CMD_1" "utf-8" iCaseSensitive To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    //  Retrieving the text also clears the receive buffer, which matters: if the next marker were
    //  left in the buffer, the following receive would match immediately.
    Get ComGetReceivedText Of hoSsh iChannelNum "utf-8" To sCmdOutput
    Get ComLastMethodSuccess Of hoSsh To bTemp1
    If (bTemp1 = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Showln sCmdOutput

    //  ---- 2nd command: directory listing ----
    Get ComChannelSendString Of hoSsh iChannelNum "ls; echo END_OF_CMD_2" + (character(10)) "utf-8" To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComChannelReceiveUntilMatch Of hoSsh iChannelNum "END_OF_CMD_2" "utf-8" iCaseSensitive To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComGetReceivedText Of hoSsh iChannelNum "utf-8" To sCmdOutput
    Get ComLastMethodSuccess Of hoSsh To bTemp1
    If (bTemp1 = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Showln sCmdOutput

    //  ---- 3rd command: long listing, then finish the session ----
    Get ComChannelSendString Of hoSsh iChannelNum "ls -l" + (character(10)) "utf-8" To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    //  No more input will be sent.
    Get ComChannelSendEof Of hoSsh iChannelNum To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComChannelReceiveToClose Of hoSsh iChannelNum To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComGetReceivedText Of hoSsh iChannelNum "utf-8" To sCmdOutput
    Get ComLastMethodSuccess Of hoSsh To bTemp1
    If (bTemp1 = False) Begin
        Get ComLastErrorText Of hoSsh To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Showln sCmdOutput

    Send ComDisconnect To hoSsh


End_Procedure