Reputation: 63
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
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