user1340106
user1340106

Reputation: 63

Unable to execute more than 1 expect send statement to remote host

I need to edit the /etc/host file on a remote PC using expect. Below is the code section:

/usr/bin/expect << EOD
    set timeout 10
    set send_slow { 1 .01 }

    spawn -noecho ssh -o StrictHostKeyChecking=no -o CheckHostIP=no -o ConnectTimeout=10 ${USRNAME}@${REMOTE_PC}
    expect  {
        timeout                 { send_user "\nTimeout while oonnecting to ${REMOTE_PC}\n"; exit }
        "*No route to host*"    { send_user "\n${REMOTE_PC} not reachable\n"; exit }
        "*assword: "            { send -s "$PASSWORD\r\r" }
    }
    expect  {
        timeout { send_user "\nTimeout waiting for prompt\n"; exit }
        # "$PS1" refers to the system prompt setup in .bash_profile.
        "$PS1"  {
            send -s "(grep -xq -P '${MY_SVR_IP}\tcm' /etc/hosts) && echo __CM_FOUND || echo __CM_NOTFOUND\r"
            expect {
                # Order is IMPORTANT! __NOTFOUND must comes first.
                __CM_NOTFOUND  {
                    send_user "\nNot Found!\n";
                    send -s "sudo sed -i -r '/127.0.0.1 +Local_Host/i # Modified on ${MOD_DATE}.' /etc/hosts \r";
                    send -s "sudo sed -i -r 's/(127.0.0.1 +Local_Host)/#\1/g' /etc/hosts \r";
                    send -s "sudo sed -i -r 's/(127.0.0.1 +cm)/#\1/g' /etc/hosts \r";
                    send -s "sudo sed -i -r '/\#127.0.0.1 +cm/a ${MY_SVR_IP}\tcm' /etc/hosts \r";
                    send "grep -B3 -A2 -P '${MY_SVR_IP}\tcm' /etc/hosts\r";
                    send_user "grep -B3 -A2 -P '${MY_SVR_IP}\tcm' /etc/hosts \r";
                    send -s "exit\r"
                }
                # Do nothing, if found. NOTE: Cannot put any comments after end brace.
                __CM_FOUND     { send -s "exit\r" }
            }
        }
    }
EOD

The script will only execute the line:

                    send -s "sudo sed -i -r '/127.0.0.1 +Local_Host/i # Modified on ${MOD_DATE}.' /etc/hosts \r";

But won't execute the subsequent lines. Why?

Appreciate any advice in advance. Thanks!

#=============================================================

I modified the script to:

/usr/bin/expect -d << EOD
    set timeout 3
    set send_slow { 1 .01 }
    set prompt_re {*${USERNAME}@${REMOTE_PC}:*\$ $}
    spawn -noecho ssh -o StrictHostKeyChecking=no -o CheckHostIP=no -o ConnectTimeout=3 ${USERNAME}@${REMOTE_PC}
    expect  {
        timeout                 { send_user "\nTimeout while oonnecting to ${REMOTE_PC}\n"; exit }
        "*No route to host*"    { send_user "\n${REMOTE_PC} not reachable\n"; exit }
        "*assword: "            { send -s "$PASSWORD\r\r" }
    }
    expect  {
        timeout { send_user "\nTimeout waiting for prompt\n"; exit }
        -re "$prompt_re" {
            send_user "\nSuccessfully login to ${REMOTE_PC}.\n"
        }
    }
    send -s "(grep -xq -P '${MY_SVR_IP}\tcm' /etc/hosts) && echo __CM_FOUND || echo __CM_NOTFOUND\r"
    expect {
        __CM_NOTFOUND  {
            send_user "\nNot Found!\n";
            send -s { "sudo sed -i -r '/127.0.0.1 +Local_Host/i # Modified on ${MOD_DATE}.' /etc/hosts \r" }
            send -s { "sudo sed -i -r 's/(127.0.0.1 +Local_Host)/#\1/g' /etc/hosts \r" }
            send -s { "sudo sed -i -r 's/(127.0.0.1 +cm)/#\1/g' /etc/hosts \r" }
            send -s { "sudo sed -i -r '/\#127.0.0.1 +cm/a ${MY_SVR_IP}\tcm' /etc/hosts \r" }
            send_user "grep -B3 -A2 -P '${MY_SVR_IP}\tcm' /etc/hosts \r"
            send -s "exit\r"
        }
        __CM_FOUND     { send -s "exit\r" }
    }
EOD

Unfortunately, it still only edit the /etc/hosts file once based on:

send -s { "sudo sed -i -r '/127.0.0.1 +Local_Host/i # Modified on ${MOD_DATE}.' /etc/hosts \r" }

Upvotes: 0

Views: 81

Answers (1)

glenn jackman
glenn jackman

Reputation: 247062

PS1 will only exist in an interactive shell.

Do you see the following in the debug output

send: sending "password\r\r" to { exp4 } 
expect: does "" (spawn_id exp4) match glob pattern ""?

That empty string is $PS1.

The idiomatic way to deal with prompts is, unfortunately, to hardcode them in a regex pattern:

# This is the patten to match a prompt on the remote host, alter as needed.
# This matches a dollar sign and a space at the end of the prompt 
set prompt_re {\$ $}

I find it help readability to avoid deeply nested expect commands:

spawn -noecho ssh -o StrictHostKeyChecking=no -o CheckHostIP=no -o ConnectTimeout=10 ${USRNAME}@${REMOTE_PC}
expect  {
    timeout                 { send_user "\nTimeout while oonnecting to ${REMOTE_PC}\n"; exit }
    "*No route to host*"    { send_user "\n${REMOTE_PC} not reachable\n"; exit }
    "*assword: "
}
send -s "$PASSWORD\r\r"
expect  {
    timeout { send_user "\nTimeout waiting for prompt\n"; exit }
    -re $prompt_re
}
send -s "(grep -xq -P '${MY_SVR_IP}\tcm' /etc/hosts) && echo __CM_FOUND || echo __CM_NOTFOUND\r"
expect {
    __CM_NOTFOUND  {
        # Order is IMPORTANT! __NOTFOUND must comes first.
        send_user "\nNot Found!\n";
        send -s "sudo sed -i -r '/127.0.0.1 +Local_Host/i # Modified on ${MOD_DATE}.' /etc/hosts \r";
        send -s "sudo sed -i -r 's/(127.0.0.1 +Local_Host)/#\1/g' /etc/hosts \r";
        send -s "sudo sed -i -r 's/(127.0.0.1 +cm)/#\1/g' /etc/hosts \r";
        send -s "sudo sed -i -r '/\#127.0.0.1 +cm/a ${MY_SVR_IP}\tcm' /etc/hosts \r";
        send "grep -B3 -A2 -P '${MY_SVR_IP}\tcm' /etc/hosts\r";
        send_user "grep -B3 -A2 -P '${MY_SVR_IP}\tcm' /etc/hosts \r";
        send -s "exit\r"
    }
    __CM_FOUND     {
        # Do nothing, if found. NOTE: Cannot put any comments after end brace.
        send -s "exit\r"
    }
}

Note DO NOT PUT COMMENTS in an expect block like that: expect will see them as pattern-action pairs. Expect sees your expect command line this:

    expect  {
        timeout { send_user "\nTimeout waiting for prompt\n"; exit }
        {#}     {"$PS1"}
        refers  {to}
        the     {system}
        prompt  {setup}
        in      {.bash_profile.}
        "$PS1"  {
            send -s "(grep -xq -P '${MY_SVR_IP}\tcm' /etc/hosts) && echo __CM_FOUND || echo __CM_NOTFOUND\r"
            expect {
                {#}            {Order}
                is             {IMPORTANT!}
                __NOTFOUND     {must}
                comes          {first.}
                __CM_NOTFOUND  {
                    send_user "\nNot Found!\n";
                    send -s "sudo sed -i -r '/127.0.0.1 +Local_Host/i # Modified on ${MOD_DATE}.' /etc/hosts \r";
                    send -s "sudo sed -i -r 's/(127.0.0.1 +Local_Host)/#\1/g' /etc/hosts \r";
                    send -s "sudo sed -i -r 's/(127.0.0.1 +cm)/#\1/g' /etc/hosts \r";
                    send -s "sudo sed -i -r '/\#127.0.0.1 +cm/a ${MY_SVR_IP}\tcm' /etc/hosts \r";
                    send "grep -B3 -A2 -P '${MY_SVR_IP}\tcm' /etc/hosts\r";
                    send_user "grep -B3 -A2 -P '${MY_SVR_IP}\tcm' /etc/hosts \r";
                    send -s "exit\r"
                }
                {#}                   {Do}
                nothing,              {if}
                found.                {NOTE:}
                Cannot                {put}
                any                   {comments}
                after                 {end}
                brace.                {__CM_FOUND}
                { send -s "exit\r" }
            }
        }
    }

Upvotes: 1

Related Questions