Visual FoxPro
Visual FoxPro
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 Visual FoxPro Downloads
LOCAL lnSuccess
LOCAL loSsh
LOCAL lcHostname
LOCAL lnPort
LOCAL lcPassword
LOCAL lnChannelNum
LOCAL lnCaseSensitive
LOCAL lcCmdOutput
lnSuccess = 0
* 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.
loSsh = CreateObject('Chilkat.Ssh')
lcHostname = "ssh.example.com"
lnPort = 22
lnSuccess = loSsh.Connect(lcHostname,lnPort)
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
* 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.
lcPassword = "mySshPassword"
lnSuccess = loSsh.AuthenticatePw("mySshLogin",lcPassword)
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
lnChannelNum = loSsh.OpenSessionChannel()
IF (lnChannelNum < 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
* 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.
lnSuccess = loSsh.SendReqShell(lnChannelNum)
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
* 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.
loSsh.ReadTimeoutMs = 15000
lnCaseSensitive = 1
* ---- 1st command: change directory ----
lnSuccess = loSsh.ChannelSendString(lnChannelNum,"cd /tmp; echo END_OF_CMD_1" + CHR(10),"utf-8")
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
lnSuccess = loSsh.ChannelReceiveUntilMatch(lnChannelNum,"END_OF_CMD_1","utf-8",lnCaseSensitive)
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
* 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.
lcCmdOutput = loSsh.GetReceivedText(lnChannelNum,"utf-8")
IF (loSsh.LastMethodSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
? lcCmdOutput
* ---- 2nd command: directory listing ----
lnSuccess = loSsh.ChannelSendString(lnChannelNum,"ls; echo END_OF_CMD_2" + CHR(10),"utf-8")
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
lnSuccess = loSsh.ChannelReceiveUntilMatch(lnChannelNum,"END_OF_CMD_2","utf-8",lnCaseSensitive)
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
lcCmdOutput = loSsh.GetReceivedText(lnChannelNum,"utf-8")
IF (loSsh.LastMethodSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
? lcCmdOutput
* ---- 3rd command: long listing, then finish the session ----
lnSuccess = loSsh.ChannelSendString(lnChannelNum,"ls -l" + CHR(10),"utf-8")
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
* No more input will be sent.
lnSuccess = loSsh.ChannelSendEof(lnChannelNum)
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
lnSuccess = loSsh.ChannelReceiveToClose(lnChannelNum)
IF (lnSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
lcCmdOutput = loSsh.GetReceivedText(lnChannelNum,"utf-8")
IF (loSsh.LastMethodSuccess = 0) THEN
? loSsh.LastErrorText
RELEASE loSsh
CANCEL
ENDIF
? lcCmdOutput
loSsh.Disconnect()
RELEASE loSsh