PureBasic
PureBasic
SSH ChannelReceiveUntilMatchN (Match Any of Several Prompts)
See more SSH Examples
Demonstrates ChannelReceiveUntilMatchN, which receives until any one of several patterns is matched. This is useful when driving an interactive session where the shell prompt differs from device to device.
Note: This example deliberately requests a PTY. Matching a shell prompt only works in an interactive session — without a PTY the shell runs non-interactively and never prints a prompt at all. For scripted use, omit the PTY and match on a marker your own command echoes.
Background: Real sessions have more than one possible next output, so waiting for one specific string risks hanging when something else appears. Matching a set lets the code proceed on whichever actually occurs — a user prompt, a root prompt, or a device-specific one. A "dumb" terminal type is requested so the remote side does not mix ANSI escape sequences into the output, which would otherwise complicate matching. Remember that retrieving text clears the receive buffer; leaving a prompt buffered would make the next receive match immediately and return the wrong output.
Chilkat PureBasic Downloads
IncludeFile "CkSsh.pb"
IncludeFile "CkStringArray.pb"
Procedure ChilkatExample()
success.i = 0
; This example requires the Chilkat API to have been previously unlocked.
; See Global Unlock Sample for sample code.
; Demonstrates ChannelReceiveUntilMatchN, which receives until ANY one of several patterns is
; matched. This is useful when driving an interactive session where the shell prompt varies
; from device to device.
;
; Note: This example deliberately DOES request a PTY. Matching a shell prompt only works in an
; interactive session -- without a PTY the shell runs non-interactively and never prints a
; prompt at all. For scripted use where no prompt is needed, omit the PTY and match on a
; marker your own command echoes instead.
ssh.i = CkSsh::ckCreate()
If ssh.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
; The remote shell prompt may be any of these, depending on the device.
saPrompts.i = CkStringArray::ckCreate()
If saPrompts.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkStringArray::ckAppend(saPrompts,"~$")
CkStringArray::ckAppend(saPrompts,"mars#")
CkStringArray::ckAppend(saPrompts,"jupiter%")
CkStringArray::ckAppend(saPrompts,"chilkat$")
CkStringArray::ckAppend(saPrompts,"admin>")
hostname.s = "ssh.example.com"
port.i = 22
success = CkSsh::ckConnect(ssh,hostname,port)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
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.
password.s = "mySshPassword"
success = CkSsh::ckAuthenticatePw(ssh,"mySshLogin",password)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
channelNum.i = CkSsh::ckOpenSessionChannel(ssh)
If channelNum < 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
; Request a pseudo-terminal so the shell runs interactively and prints prompts. A "dumb"
; terminal is used so that ANSI escape sequences are not mixed into the output.
termType.s = "dumb"
widthInChars.i = 120
heightInChars.i = 40
pixWidth.i = 0
pixHeight.i = 0
success = CkSsh::ckSendReqPty(ssh,channelNum,termType,widthInChars,heightInChars,pixWidth,pixHeight)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
success = CkSsh::ckSendReqShell(ssh,channelNum)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
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.
CkSsh::setCkReadTimeoutMs(ssh, 15000)
caseSensitive.i = 1
; Read the initial login text up to the first prompt.
success = CkSsh::ckChannelReceiveUntilMatchN(ssh,channelNum,saPrompts,"utf-8",caseSensitive)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
cmdOutput.s = CkSsh::ckGetReceivedText(ssh,channelNum,"utf-8")
If CkSsh::ckLastMethodSuccess(ssh) = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
Debug cmdOutput
; ---- 1st command ----
success = CkSsh::ckChannelSendString(ssh,channelNum,"cd /tmp" + Chr(10),"utf-8")
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
success = CkSsh::ckChannelReceiveUntilMatchN(ssh,channelNum,saPrompts,"utf-8",caseSensitive)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
; Retrieving the text also clears the receive buffer, which matters: if a prompt were left
; buffered, the next receive would match it immediately and return the wrong output.
cmdOutput = CkSsh::ckGetReceivedText(ssh,channelNum,"utf-8")
If CkSsh::ckLastMethodSuccess(ssh) = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
Debug cmdOutput
; ---- 2nd command ----
success = CkSsh::ckChannelSendString(ssh,channelNum,"ls" + Chr(10),"utf-8")
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
success = CkSsh::ckChannelReceiveUntilMatchN(ssh,channelNum,saPrompts,"utf-8",caseSensitive)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
cmdOutput = CkSsh::ckGetReceivedText(ssh,channelNum,"utf-8")
If CkSsh::ckLastMethodSuccess(ssh) = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
Debug cmdOutput
; Finish the session.
success = CkSsh::ckChannelSendEof(ssh,channelNum)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
success = CkSsh::ckChannelReceiveToClose(ssh,channelNum)
If success = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
cmdOutput = CkSsh::ckGetReceivedText(ssh,channelNum,"utf-8")
If CkSsh::ckLastMethodSuccess(ssh) = 0
Debug CkSsh::ckLastErrorText(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndIf
Debug cmdOutput
CkSsh::ckDisconnect(ssh)
CkSsh::ckDispose(ssh)
CkStringArray::ckDispose(saPrompts)
ProcedureReturn
EndProcedure