Sample code for 30+ languages & platforms
C++

Receive from an SSH Channel Until a Pattern Matches

See more SSH Examples

Demonstrates the Chilkat Ssh.ChannelReceiveUntilMatch method, which receives text until the accumulated text matches a pattern. The arguments are the channel number, the pattern, the charset, and whether matching is case-sensitive. Existing buffered text is checked before waiting for more network data.

Important: Set the ReadTimeoutMs property before calling this method. It defaults to 0, meaning no limit, so without it the call waits forever if the received data never contains a match.

Background: Driving a shell channel means knowing when the remote side has finished talking. With no PTY requested the shell is non-interactive and never prints a prompt, so the reliable signal is a marker you deliberately echo after your command. This method automates "read until you see X." The pattern syntax is deliberately minimal: literal characters plus *, which matches zero or more characters and can span line breaks. ? and bracket classes are not supported, and backslash does not escape a literal *.

Chilkat C++ Downloads

C++
#include <CkSsh.h>

void ChilkatSample(void)
    {
    bool success = false;

    //  Demonstrates the Ssh.ChannelReceiveUntilMatch method, which receives text until the
    //  accumulated text matches a pattern.  The 1st argument is the channel number, the 2nd is the
    //  pattern, the 3rd is the charset, and the 4th selects case-sensitive matching.  The pattern
    //  supports literal characters plus "*", which matches zero or more characters.

    CkSsh ssh;

    int sshPort = 22;
    success = ssh.Connect("ssh.example.com",sshPort);
    if (success == false) {
        std::cout << ssh.lastErrorText() << "\r\n";
        return;
    }

    //  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.
    const char *password = "mySshPassword";

    success = ssh.AuthenticatePw("mySshLogin",password);
    if (success == false) {
        std::cout << ssh.lastErrorText() << "\r\n";
        return;
    }

    int channelNum = ssh.OpenSessionChannel();
    if (channelNum < 0) {
        std::cout << ssh.lastErrorText() << "\r\n";
        return;
    }

    //  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.
    success = ssh.SendReqShell(channelNum);
    if (success == false) {
        std::cout << ssh.lastErrorText() << "\r\n";
        return;
    }

    //  There is no prompt to wait for, so make the command itself announce when it has finished
    //  by echoing a marker after it.
    success = ssh.ChannelSendString(channelNum,"ls -l /tmp; echo DONE_MARKER\n","utf-8");
    if (success == false) {
        std::cout << ssh.lastErrorText() << "\r\n";
        return;
    }

    //  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.
    ssh.put_ReadTimeoutMs(15000);

    //  Receive until the marker appears in the output.
    bool caseSensitive = false;
    success = ssh.ChannelReceiveUntilMatch(channelNum,"DONE_MARKER","utf-8",caseSensitive);
    if (success == false) {
        std::cout << ssh.lastErrorText() << "\r\n";
        return;
    }

    const char *output = ssh.getReceivedText(channelNum,"utf-8");
    if (ssh.get_LastMethodSuccess() == false) {
        std::cout << ssh.lastErrorText() << "\r\n";
        return;
    }

    std::cout << output << "\r\n";

    ssh.Disconnect();
    }