I'm not understanding the runtime behavior of Expect. My goal is to execute some commands, ignore the output so far and then match a send output against an expect expression following. Expect tries to match this expression still against the first send statements which is matching an incorrect result. How can expect be forced to look only into the last send statement?
#!/usr/bin/env expect -f
log_user 0
# for debugging
exp_internal 1
spawn gpshell
expect *
send "establish_context\r"
expect *
send "enable_trace\r"
expect *
send "card_connect\r"
expect *
send "send_apdu -sc 0 -APDU 00a40004023f00\r"
expect *
send "send_apdu -sc 0 -APDU 00a40804022fe2\r"
expect *
send "send_apdu -sc 0 -APDU 00B000000A\r"
expect -indices -re {(?n)<-- ([0-9]+).*$}
set iccid $expect_out(1,string)
puts $iccid
send "card_disconnect\r"
send "release_context\r"
send \x03
exit 0
Debug output:
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {1640670}
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "establish_context\r" to { exp4 }
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "enable_trace\r" to { exp4 }
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "card_connect\r" to { exp4 }
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "send_apdu -sc 0 -APDU 00a40004023f00\r" to { exp4 }
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "send_apdu -sc 0 -APDU 00a40804022fe2\r" to { exp4 }
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "send_apdu -sc 0 -APDU 00B000000A\r" to { exp4 }
Gate keeper glob pattern for '(?n)<-- ([0-9]+).*$' is '<-- *'. Activating booster.
expect: does "" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=no
expect: does "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\n" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=no
expect: does "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\nenable_trace\r\ncard_connect\r\n" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=no
expect: does "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\nenable_trace\r\ncard_connect\r\n* reader name Virtual PCD 00 00\r\n" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=no
expect: does "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\nenable_trace\r\ncard_connect\r\n* reader name Virtual PCD 00 00\r\n* reader name Virtual PCD 00 01\r\n" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=no
expect: does "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\nenable_trace\r\ncard_connect\r\n* reader name Virtual PCD 00 00\r\n* reader name Virtual PCD 00 01\r\n* reader name OMNIKEY CardMan 5321 00 00\r\n" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=no
expect: does "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\nenable_trace\r\ncard_connect\r\n* reader name Virtual PCD 00 00\r\n* reader name Virtual PCD 00 01\r\n* reader name OMNIKEY CardMan 5321 00 00\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nCommand --> 00A40004023F00\r\nWrapped command --> 00A40004023F00\r\n" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=no
expect: does "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\nenable_trace\r\ncard_connect\r\n* reader name Virtual PCD 00 00\r\n* reader name Virtual PCD 00 01\r\n* reader name OMNIKEY CardMan 5321 00 00\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nCommand --> 00A40004023F00\r\nWrapped command --> 00A40004023F00\r\nResponse <-- 62288202782183023F00A50B8001718303078ED08701018A01058B032F060EC60990018083010A8301019000\r\nUnwrapped response <-- 62288202782183023F00A50B8001718303078ED08701018A01058B032F060EC60990018083010A8301019000\r\nsend_APDU() returns 0x80209000 (Success)\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nCommand --> 00A40804022FE2\r\nWrapped command --> 00A40804022FE2\r\n" (spawn_id exp4) match regular expression "(?n)<-- ([0-9]+).*$"? Gate "<-- *"? gate=yes re=yes
expect: set expect_out(0,start) "423"
expect: set expect_out(0,end) "515"
expect: set expect_out(0,string) "<-- 62288202782183023F00A50B8001718303078ED08701018A01058B032F060EC60990018083010A8301019000\r"
expect: set expect_out(1,start) "427"
expect: set expect_out(1,end) "443"
expect: set expect_out(1,string) "62288202782183023"
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "establish_context\r\nenable_trace\r\ncard_connect\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nsend_apdu -sc 0 -APDU 00a40804022fe2\r\nsend_apdu -sc 0 -APDU 00B000000A\r\nestablish_context\r\nenable_trace\r\ncard_connect\r\n* reader name Virtual PCD 00 00\r\n* reader name Virtual PCD 00 01\r\n* reader name OMNIKEY CardMan 5321 00 00\r\nsend_apdu -sc 0 -APDU 00a40004023f00\r\nCommand --> 00A40004023F00\r\nWrapped command --> 00A40004023F00\r\nResponse <-- 62288202782183023F00A50B8001718303078ED08701018A01058B032F060EC60990018083010A8301019000\r"
send: sending "card_disconnect\r" to { exp4 }
send: sending "release_context\r" to { exp4 }
send: sending "\u0003" to { exp4 }
The 62288202782183023 is from an earlier command, not from the one after which I have added the expectation.
The typical automation sequence is:
spawn ...
expect something
send "...\r"
expect something
send "...\r"
expect something
... and so on, so that after each command you type, you wait for the spawned process to respond. It allows you to gather up whatever the process outputs, and discard it if you don't care about it.
The first expect after spawn is important. You know at that point that the spawned process is ready to receive a command.
Typically, you're automating some kind of shell. The something that you expect is usually some kind of prompt.
Related
Currently facing an issue, which I fail to explain.
Using TCL Expect to send a command to a remote telnet device, which is running on linux(busybox). The command has a confirmation echo ending like
'&& echo helloMyNameIsCarl'.
When i'm trying to verify that the command has been send, the debug of TCL Expect's "expect" is giving me:
"helloMyNameI\n\n\nsCarl"
Same thing, triggered from another PC(not the destination device, but the source), is doing well - the reply is without the '\n\n...'. And the troublesome source device didn't have any issues until it's network adapter was replaced.
Example:
package require Expect
spawn telnet 192.168.1.1
set telnetId $spawn_id
exp_internal 1
puts $telnetId "get_linux_env_params_random_command && echo 11223344556677"
expect "11223344556677"; #verifying the command was fully sent to the device
expect "11223344556677"; #verifying the echo respond
And the debug of the expect will be:
expect: does "# get_linux_env_para " (spawn_id exp4) match glob pattern "get_linux_env_params_random_command && echo 11223344556677"
? no
expect: does "# get_linux_env_params_random_command && echo 11" (spawn_id exp4) match glob pattern "get_linux_env_params_random_command && echo 11223344556677"? no
expect: does "# get_linux_env_params_random_command && echo 11223344" (spawn_id exp4) match glob pattern "get_linux_env_params_random_command && echo 11223344556677"? no
expect: does "# get_linux_env_params_random_command && echo 11223344\n\n" (spawn_id exp4) match glob pattern "get_linux_env_params_random_command && echo 11223344556677"? no
expect: does "# get_linux_env_params_random_command && echo 11223344\n\n5\n5\n6677\n\n" (spawn_id exp4) match glob pattern "get_linux_env_params_random_command && echo 11223344556677"? no
Any suggestions on this?
I have copied my script below. For the variable "userName" I am not getting expected output at correct place. The expected output is "pload", it is coming at the end. Any suggestion on this to get correctly ?
script:
#!/usr/bin/expect
exp_internal 1
set timeout 30
set prompt {[$]}
spawn ssh -o StrictHostKeyChecking=no $username#$server.com
expect "assword"
send $password\r
expect "$prompt"
expect *
send "ps aux | grep -v grep | tr ' ' '\\n' | grep pload | uniq\r"
expect -re "(.*)\n"
sleep 20
set userName $expect_out(buffer)
puts "buffer:$userName end"
if { $userName eq "pload" } {
send "sudo su - pload\r"
} else {
send "sudo su - pdev\r"
}
expect "assword"
send $password\r
expect "$prompt"
Below is log:
.
.
3997#fd0441a2:~\u0007\u001b[?1034h[f5103997#fd0441a2 ~]$"
expect: does " " (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) " "
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) " "
send: sending "ps aux | grep -v grep | tr ' ' '\n' | grep pload | uniq\r" to { exp4 }
Gate keeper glob pattern for '(.*)
' is '*
'. Activating booster.
expect: does "" (spawn_id exp4) match regular expression "(.*)\n"? Gate "*\n"? gate=no
ps aux | grep -v grep | tr ' ' '\n' | grep pload | uniq
expect: does "ps aux | grep -v grep | tr ' ' '\n' | grep pload | uniq\r\n" (spawn_id exp4) match regular expression "(.*)\n"? Gate "*\n"? gate=yes re=yes
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "ps aux | grep -v grep | tr ' ' '\n' | grep pload | uniq\r\n"
buffer:ps aux | grep -v grep | tr ' ' '\n' | grep pload | uniq
end
send: sending "sudo su - pdev\r" to { exp4 }
expect: does "" (spawn_id exp4) match glob pattern "assword"? no
pload
[f5103997#fd0441a2 ~]$
expect: does "pload\r\n\u001b]0;f5103997#fd0441a2:~\u0007[f5103997#fd0441a2 ~]$ " (spawn_id exp4) match glob pattern "assword"? no
sudo su - pdev
I usually put some special chars around the command's output so it's a bit easier to write an expect RE. So try like this:
send "echo ==\">\$(ps aux | grep -v grep | tr ' ' '\\n' | grep pload | uniq)<\"==\r"
expect -re "==>(.*)<=="
set userName $expect_out(1,string)
# ^^^^^^^^
expect "$prompt"
I suggest some edits to the expect code:
Use expect -re and use patterns. For e.g., the prompt is set to [f5103997#fd0441a2 ~]$ but the pattern to match is [$]. expect -re {.*$]\s*} is better, IMO.
Change the default prompt to a known value (without any TCL special characters (like $ and [) immediately after 1st login. The next set of commands should execute smoothly. I tried it, here's a snippet:
expect -re {.*[pP]assword}
send $password\r
expect -re "$prompt"
set newPrompt {MY_NEW_PROMPT> }
send "export PS1=\"$newPrompt\"\r"
expect -re ".*$newPrompt"
send "\r"
after 2000 ;# flush out the MOTD, etc.
expect -re ".*$newPrompt"
send "pwd\r"
expect -re ".*$newPrompt"
puts -->$expect_out(buffer)
send "exit\r"
Output:
sharad#sharad:~$ expect sharad.expect
spawn ssh -o StrictHostKeyChecking=no sharad#localhost
sharad#localhost's password:
export PS1="MY_NEW_PROMPT> "
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-53-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
175 packages can be updated.
4 updates are security updates.
export PS1="MY_NEW_PROMPT> "
Last login: Fri Dec 23 23:02:22 2016 from 127.0.0.1
sharad#sharad:~$ export PS1="MY_NEW_PROMPT> "
MY_NEW_PROMPT>
MY_NEW_PROMPT> pwd
/home/sharad
MY_NEW_PROMPT> -->pwd
/home/sharad
MY_NEW_PROMPT>
sharad#sharad:~$
Can anyone help me with the following. I think it could be due to whitespace but for the life of me I can't figure it out.
This is supposed to be a simple script that will move a file depending on it's location. I'm using expect as I want it to be handled on my NAS (via ssh), rather than taking the file off and putting it back on just to move it between shares.
#!/usr/bin/expect -f
# Script to organise downloaded file
set FileDir [lindex $argv 0]
set FileName [lindex $argv 1]
set MiscDir "/media/Misc/Downloads"
set DownDir "/media/Downloads"
if { [string compare $FileDIR $DownDir] = 0 } {
} elseif { [string compare $FileDIR $MiscDir] = 0 } {
spawn ssh *****#*******
expect "assword:"
send "********\r"
expect "$ "
send "mv ~/Misc/Downloads/$FileNAME '~/Misc/To Convert/$FileNAME'"
expect "$ "
send "exit\r"
expect eof'
}
Updated Code:
#!/usr/bin/expect -f
# Script to organise downloaded file
set FileDir [lindex $argv 0]
set FileName [lindex $argv 1]
set MiscDir "/media/Misc/Downloads"
set DownDir "/media/Downloads"
if { [string compare $FileDir $DownDir] == 0 } {
} elseif { [string compare $FileDir $MiscDir] == 0 } {
set OrigFile "\"/shares/Misc/Downloads/$FileName\""
set MoveFile "\"/shares/Misc/To Convert/$FileName\""
spawn ssh Admin#Appledore
expect "assword:"
send "xxxxxxxx\r"
expect "$ "
send "mv $OrigFile $MoveFile"
expect "$ "
send "exit\r"
expect eof'
}
Debug Output
spawn ssh Admin#Appledore parent: waiting for sync byte parent: telling child to go ahead parent: now unsynchronized from child spawn: returns {5222}
expect: does "" (spawn_id exp6) match glob pattern "assword:"? no Admin#appledore's password: expect: does "Admin#appledore's password: " (spawn_id exp6) match glob pattern "assword:"? yes expect: set expect_out(0,string) "assword:" expect: set expect_out(spawn_id) "exp6" expect: set expect_out(buffer) "Admin#appledore's password:" send: sending "*******!\r" to { exp6 }
expect: does " " (spawn_id exp6) match glob pattern "$ "? no
expect: does " \r\n" (spawn_id exp6) match glob pattern "$ "? no [Admin#Appledore ~]$ expect: does " \r\n[Admin#Appledore ~]$ " (spawn_id exp6) match glob pattern "$ "? yes expect: set expect_out(0,string) "$ " expect: set expect_out(spawn_id) "exp6" expect: set expect_out(buffer) " \r\n[Admin#Appledore ~]$ " send: sending "mv "/shares/Misc/Downloads/NOOBS_lite_v1_4.zip" "/shares/Misc/To Convert/NOOBS_lite_v1_4.zip"" to { exp6 }
expect: does "" (spawn_id exp6) match glob pattern "$ "? no <ownloads/NOOBS_lite_v1_4.zip" "/shares/Misc/To Convert/NOOBS_lite_v1_4.zip" expect: does "mv "/shares/Misc/Downloads/NOOBS_lite_v1_4.zip" "/shares/Misc/To Convert/NOOBS_lite_v1_4.zip\r<ownloads/NOOBS_lite_v1_4.zip" "/shares/Misc/To Convert/NOOBS_lite_v1_4.zip" \u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008\u0008" (spawn_id exp6) match glob pattern "$ "? no
change your = to ==
= is usually for assignment (and doesn't work in tcl. as commented below)
== is test for equalness
I dont know whats happening but i am not getting the complete output from the remote command executed possibly because expects internal buffer is getting execceded.
proc SendCommands { Commands } {
global prompt log errlog
foreach element [split $Commands ";"] {
expect {
-re $prompt
{send -- "$element\r"}
}
set outcome "$expect_out(buffer)"
foreach line [split $outcome \n] {
foreach word [regexp -all -inline {\S+} $line] {
if {( [string index [string trimleft $line " "] 0 ] == "%")} {
puts "$outcome"
exit 1
}
}
}
puts "$outcome"
}
}
set timeout 30
foreach host [ split $hosts "\;" ] {
spawn ssh -o "StrictHostKeyChecking no" "$username#$host"
match_max 10000000
expect {
timeout { send_user "\nFailed to get password prompt\n"; exit 1 }
eof { send_user "\nSSH failure for $host\n"; exit 1 }
"*?assword:*"
{
send -- "$password\r"
}
}
expect {
timeout { send_user "\nLogin incorrect\n"; exit 1 }
eof { send_user "\nSSH failure for $host\n"; exit 1 }
-re "$prompt"
{ send -- "\r" }
}
set timeout 300
SendCommands "$Commands"
}
this is how i am executing it :
./sendcommand aehj SWEs-elmPCI-B-01.tellus comnet1 "terminal length 0;show int description" "(.*#)$"
i am getting the complete output only when i remove log user 0 but when i use the puts command in the fucnction sendcommands above i get about 90 percent of it with 10 percent
of the trailing data at the end is not shown.
one way i am thinking is to use negation of regex in expect but it doesn't seem to work.
expect {
-re ! $prompt
{puts $expect_outcome(buffer)}
}
EDIT :I get all the output once when its executed about 5 or 7 times
After a little search i came up with this and seems to work but let me know of any execptions or better answers :
I set match_max = 1000 then
expect {
-re $prompt
{send -- "$element\r"}
full_buffer {
append outcome $expect_out(buffer)
exp_continue
}
}
append outcome $expect_out(buffer)
puts $outcome
but still when i set match_max = 10000 or 100 it fails again
I want to write a generic expect script to login through SSH to a system and execute some commands. An example I found had the following:
#!/usr/bin/expect
set fid [open ./.secret]
set password [read $fid]
close $fid
spawn /usr/bin/ssh root#[lindex $argv 0]
expect {
-re ".*Are.*.*yes.*no.*" {
send "yes\n"
exp_continue
#look for the password prompt
}
"*?assword:*" {
send $password
send "\n"
}
}
send -- "PS1='>'\r"
expect -re ">$" { send "hostname\r" }
expect -re ">$" { send "pwd\r" }
...the script seems to login properly but it didn't execute the last 2 sends. Ideas?
Edit:
After enabling exp_internal, I noticed the following:
expect: does "" (spawn_id exp4) match glob pattern "*"? yes
expect: set expect_out(0,string) ""
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) ""
send: sending "PS1='>'\r" to { exp4 }
Gate keeper glob pattern for '>$' is '>'. Activating booster.
expect: does "" (spawn_id exp4) match regular expression ">$"? Gate ">"? gate=no
expect: does "\r\n" (spawn_id exp4) match regular expression ">$"? Gate ">"? gate=no
Last login: Tue Nov 6 14:13:31 2012 from 1.x.x.x
expect: does "\r\nLast login: Tue Nov 6 14:13:31 2012 from 1.x.x.x\r\r\n" (spawn_id exp4) match regular expression ">$"? Gate ">"? gate=no
I'm trying to send PS1='>'\r because I want to override the prompt. I don't think there's any way for me to predict what the prompt will be and therefore, I wouldn't know what pattern to expect. From the above, it looks like the prompt wasn't changed. How do you tackle a problem like this?
There doesn't appear to be anything obviously wrong with your script (though using a different prompt might make matching a bit easier). Which means it is something subtle. I suggest adding this:
exp_debug 1
to somewhere early in your script. It will make the Expect engine print a lot more about what it is doing, which will (probably) help you understand what is going wrong, or failing that help the people here help you…