Expect: regexp to include various shell prompts - tcl

I use:
set prompt {[#>$%]}
...
expect -re $prompt
...
but this doesn't always detect some prompts such as:
/home/user1$
root#
bash-4>
etc.
Is it possible to make a regexp detect all and any prompts?
Thanks very much in advance!
Below shows the entire output when using expect -d, as Glenn and sexpect suggested:
It took sometime for me to find a way to avoid the error and finally include this long output as a code. Sorry for the delay, and thank you again!
spawn ssh -t user#example.net
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {36}
expect: does "" (spawn_id exp8) match glob pattern "assword: "? no
"(yes/no)?"? no
"closed by remote host"? no
(user#example.net) Password:
expect: does "\r(user#example.net) Password: " (spawn_id exp8) match glob pattern "assword: "? yes
expect: set expect_out(0,string) "assword: "
expect: set expect_out(spawn_id) "exp8"
expect: set expect_out(buffer) "\r(user#example.net) Password: "
send: sending "MyNewP#$$w#rd\r" to { exp8 }
expect: continuing expect
expect: does "" (spawn_id exp8) match glob pattern "assword: "? no
"(yes/no)?"? no
"closed by remote host"? no
expect: does "\r\n" (spawn_id exp8) match glob pattern "assword: "? no
"(yes/no)?"? no
"closed by remote host"? no
Last successful login: Thu Dec 15 08:34:08 PST 2022 10.10.10.131
Last authentication failure: Fri Dec 9 16:09:53 PST 2022 10.10.10.237
Last login: Thu Dec 15 08:34:10 2022 from 10.10.10.151
expect: does "\r\nLast successful login: Thu Dec 15 08:34:08 PST 2022 10.10.10.131 \r\nLast authentication failure: Fri Dec 9 16:09:53 PST 2022 10.10.10.237 \r\nLast login: Thu Dec 15 08:34:10 2022 from 10.10.10.131\r\r\n" (spawn_id exp8) match glob pattern "assword: "? no
"(yes/no)?"? no
"closed by remote host"? no
bash-4.3$
expect: does "\r\nLast successful login: Thu Dec 15 08:34:08 PST 2022 10.10.10.131 \r\nLast authentication failure: Fri Dec 9 16:09:53 PST 2022 10.10.10.237 \r\nLast login: Thu Dec 15 08:34:10 2022 from 10.10.10.131\r\r\nbash-4.3$ " (spawn_id exp8) match glob pattern "assword: "? no
"(yes/no)?"? no
"closed by remote host"? no
expect: timed out
Gate keeper glob pattern for '[#>$%]' is ''. Not usable, disabling the performance booster.
expect: does "\r\nLast successful login: Thu Dec 15 08:34:08 PST 2022 10.10.10.131 \r\nLast authentication failure: Fri Dec 9 16:09:53 PST 2022 10.10.10.237 \r\nLast login: Thu Dec 15 08:34:10 2022 from 10.10.10.131\r\r\nbash-4.3$ " (spawn_id exp8) match regular expression "[#>$%]"? (No Gate, RE only) gate=yes re=yes
expect: set expect_out(0,string) "$"
expect: set expect_out(spawn_id) "exp8"
expect: set expect_out(buffer) "\r\nLast successful login: Thu Dec 15 08:34:08 PST 2022 10.10.10.131 \r\nLast authentication failure: Fri Dec 9 16:09:53 PST 2022 10.10.10.237 \r\nLast login: Thu Dec 15 08:34:10 2022 from 10.10.10.131\r\r\nbash-4.3$"
send: sending "sudo passwd root\r" to { exp8 }
Gate keeper glob pattern for '(N|n)ew (P|p)assword: ' is ''. Not usable, disabling the performance booster.
expect: does " " (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
sud
expect: does " sud" (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
o passwd root
expect: does " sudo passwd root\r\n" (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
Changing password for root
expect: does " sudo passwd root\r\nChanging password for root\r\n" (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
New password:
expect: does " sudo passwd root\r\nChanging password for root\r\nNew password: " (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=yes
expect: set expect_out(0,string) "New password: "
expect: set expect_out(1,string) "N"
expect: set expect_out(2,string) "p"
expect: set expect_out(spawn_id) "exp8"
expect: set expect_out(buffer) " sudo passwd root\r\nChanging password for root\r\nNew password: "
send: sending "MyNewP#$$w#rd\r" to { exp8 }
expect: continuing expect
expect: does "" (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
expect: does "\r\n" (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
Re-enter new password:
expect: does "\r\nRe-enter new password: " (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=yes
expect: set expect_out(0,string) "new password: "
expect: set expect_out(1,string) "n"
expect: set expect_out(2,string) "p"
expect: set expect_out(spawn_id) "exp8"
expect: set expect_out(buffer) "\r\nRe-enter new password: "
send: sending "MyNewP#$$w#rd\r" to { exp8 }
expect: continuing expect
expect: does "" (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
expect: does "\r\n" (spawn_id exp8) match regular expression "(N|n)ew (P|p)assword: "? (No Gate, RE only) gate=yes re=no
"Password:"? no
"again:"? no
"Segmentation Fault"? no
expect: timed out
Gate keeper glob pattern for '[#>$%]' is ''. Not usable, disabling the performance booster.
expect: does "\r\n" (spawn_id exp8) match regular expression "[#>$%]"? (No Gate, RE only) gate=yes re=no
expect: timed out
send: sending "exit\r" to { exp8 }
exit
Passwd successfully changed
bash-4.3$ exit
exit
expect: read eof
expect: set expect_out(spawn_id) "exp8"
expect: set expect_out(buffer) "\r\nexit\r\nPasswd successfully changed\r\nbash-4.3$ exit\r\nexit\r\n"

Prompts can be literally arbitrary strings (they're user-configurable and ending with $ or # is merely a common convention) so there isn't a way to match all of them that won't also pick up literally everything else as a prompt. You can usually avoid the worst problems by setting the environment variable TERM to dumb prior to calling spawn (so you probably don't get escape codes in the prompt!) but ultimately the prompt matcher may just have to be written to the specific system (or systems) that you have.
This sort of thing is part of why sharing expect scripts is actually quite difficult; the details of the systems being automated tend to sabotage our efforts!

Related

Bash script iterate through file and delete block of text using sed

I have a JSON file with the following contents:
[
{
"url" : "www.google.com",
"valid_from" : " Jul 31 10:16:13 2017 GMT",
"valid_till" : " Jul 31 10:16:13 2019 GMT",
"validity" : "Valid",
"days" : "464"
},
{
"url" : "www.youtube.com",
"valid_from" : " Apr 9 12:12:17 2017 GMT",
"valid_till" : " Apr 9 12:12:17 2019 GMT",
"validity" : "Valid",
"days" : "351"
}
]
I want to delete a block of JSON by passing a url argument corresponding to the block to delete.
I have a script cert-check-script-delete.sh which contains the following code:
line_num=1
cat certs.json >> certs-new.json
while read p; do # Iterate through each line in certs.json
if [[ $p == *"$1"* ]]; # Check if current line contains argument
then
sed -i "${line_num-1}d" certs-new.json # {
sed -i "${line_num}d" certs-new.json # Url
sed -i "${line_num+1}d" certs-new.json # Valid from
sed -i "${line_num+2}d" certs-new.json # Valid till
sed -i "${line_num+3}d" certs-new.json # Validity
sed -i "${line_num+4}d" certs-new.json # Days
sed -i "${line_num+5}d" certs-new.json # }
break
fi
((line_num++))
done <certs.json
mv certs-new.json certs.json
And after running my script with argument www.youtube.com I'm getting weird behaviour where it seems to just be deleting random lines:
{
"valid_from" : " Jul 31 10:16:13 2017 GMT",
"validity" : "Valid",
{
"valid_till" : " Apr 9 12:12:17 2019 GMT",
"validity" : "Valid",
"days" : "351"
}
]
I know I should use jq for inserting/deleting JSON but I'm not able to install it at work, so please don't just comment saying use jq.
Any help is appreciated!
You can do it like below:-
sed -i '/www.youtube.com/I,+6 d;$!N;/www.youtube.com/!P;D' certs-new.json
If your search string has been provided as command line parameter use like
sed -i '/'$1'/I,+6 d;$!N;/'$1'/!P;D' certs-new.json
How will it work, First it will search for pattern www.youtube.com and delete 6 lines below the pattern and second part of sed command will search for pattern www.youtube.com and delete the pattern line and one line above it.
In your example the output will be:-
[
{
"url" : "www.google.com",
"valid_from" : " Jul 31 10:16:13 2017 GMT",
"valid_till" : " Jul 31 10:16:13 2019 GMT",
"validity" : "Valid",
"days" : "464"
},
]

Expect script ends without error at the New Password prompt

I have Solaris servers of which I'm not sure if I changed the password to a particular account. Either I'm going to authenticate successfully because I already changed the password or I'm going to authenticate with the old password and it will prompt me to change my password after I authenticate with the old password because it expired.
Warning: Your password has expired, please change it now.
New Password:
The script will stop at the New Password: prompt and exits w/o an error.
#!/bin/bash
NewPassword="cccccc"
OtherPassword="ffffffff"
for i in `cat x.txt`
do
/opt/csw/bin/expect -f <(cat << EOF
spawn ssh -o StrictHostKeyChecking=no adminuser#$i
expect "Password: "
send "$NewPassword\r"
expect {
"$ " {
## new password worked
send "uname -a\r"
}
"Password: " {
## The new password did not work
send "$OtherPassword\r"
expect "$ "
}
"New Password: " {
## after authenticating, my old password expired need to change it now
send ${NewPassword}\r
expect "Re-enter new Password: "
send ${NewPassword}\r
expect "$ "
}
}
EOF
)
done
The order of clauses in the expect matters; the internal matcher tries the different matching rules in the order you specify. This is important here because the rule for Password: also matches what New Password: will match, and so will have priority over it.
Swap the two clauses or rewrite them so that they can't both match the same input text (probably by including the newline or changing to using anchored regular expressions). Swapping them is far easier.
In addition to Donal's cogent advice, a couple of notes:
In the shell part, don't read lines with for
using a process substitution and cat and a here document is overkill: you just need the here-doc
use exp_continue to handle the exceptional cases that occur before you see the prompt
exit your login session and expect to see it close so you don't have to wait around to timeout.
#!/bin/bash
NewPassword="cccccc"
OtherPassword="ffffffff"
while read server; do
/opt/csw/bin/expect << EOF
spawn ssh -o StrictHostKeyChecking=no adminuser#$server
expect "Password: "
send "$NewPassword\r"
set count 0
expect {
"New Password: " {
## after authenticating, my old password expired need to change it now
send ${NewPassword}\r
expect "Re-enter new Password: "
send ${NewPassword}\r
exp_continue
}
"Password: " {
if {[incr count] == 2} {
error "neither new password nor old password worked for $server"
}
## The new password did not work
send "$OtherPassword\r"
exp_continue
}
"$ "
}
send "uname -a\r"
expect "$ "
send "exit\r"
expect eof
EOF
done < x.txt

Expect: SSH into a remote host, run a command, and save its output to a variable

I'm trying to ssh into a server, run a command, and save its output to a variable, with no success.
spawn $env(SHELL)
expect "\$ "
send "ls\r"
expect "\$ "
send "ssh myserver1\r"
expect "\$ "
send "cd /tmp/remotedir1\r"
expect "\$ "
send "ls\r"
expect "\$ "
set myvar1 [exec ls]
puts "The value of \$myvar1 is: "
puts $myvar1
send "exit\r"
expect "\$ "
send "exit\r"
expect eof
When I run it, I get:
spawn /bin/bash
$ ls
localfile1 localfile2 localfile3
$ ssh myserver1
Last login: Tue Sep 10 15:45:07 2017 from 192.168.0.100
myserver1$ cd /tmp/remotedir1
myserver1$ ls
remotefile1
myserver1$ The value of $myvar1 is:
localfile1
localfile2
localfile3
exit
logout
Connection to myserver1 closed.
bash-3.2$ exit
exit
Apparently, instead of setting $myvar1 to "remotefile1", it sets to those 3 files in the $cwd on the local host.
Thank you for your help in advance!
Using exec will execute the command locally.
Upon sending the ls command, you have to make use of the expect_out array to get the response.
set prompt "(.*)(#|%|>|\\\$) $"
send "ls\r"
expect -re $prompt
puts $expect_out(1,string)

Am I missing the target with exp_continue?

I'm trying to write an expect script that allows me to ssh into a switch, look for a certain set of software in flash, then delete it. I would like to say that if you see result "A" do action "B", and if you see result "C" do action "B". All of these results are displayed when I run one command.
This is an example of a result I'm expecting.
B3898_RM23_SW1#dir ?
/all List all files
/recursive List files recursively
all-filesystems List files on all filesystems
bs: Directory or file name
cns: Directory or file name
flash1: Directory or file name
flash2: Directory or file name
flash: Directory or file name
null: Directory or file name
nvram: Directory or file name
system: Directory or file name
tar: Directory or file name
tmpsys: Directory or file name
vb: Directory or file name
xmodem: Directory or file name
ymodem: Directory or file name
<cr>
B3898_RM23_SW1#
What I'm looking for is the "flash1:" directory. Now there is a possibility of their being a total of nine flash file systems. You'll always have "flash1:"; what I want to do is go into each of the possible directories and delete either a file or an entire directory. And if their is no other directories just to move on.
What I want to know is how to properly use exp_continue, or if I need to use it at all in this instance. This is what I've got written, and it will copy the software to flash1, but if flas2 and so on exist it wont copy or delete the software over to the other flashes.
send "dir ?\r"
expect {
-re {\mflash1\M} {
send "delete /force /recursive flash1:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash1:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {\mflash2\M} {
send "delete /force /recursive flash2:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash2:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {\mflash3\M} {
send "delete /force /recursive flash3:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash3:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {\mflash4\M} {
send "delete /force /recursive flash4:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash4:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {\mflash5\M} {
send "delete /force /recursive flash5:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash5:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {mflash6\M} {
send "delete /force /recursive flash6:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash6:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {\mflash7\M} {
send "delete /force /recursive flash7:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash7:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {\mflash8\M} {
send "delete /force /recursive flash8:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash8:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
-re {\mflash9\M} {
send "delete /force /recursive flash9:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive flash9:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
}
#This deletes the IOS from a single device, then tftps the IOS to flash. If the TFTP fails it tries one more time.
send "copy tftp: flash1:\r"
expect "Address or name of remote host []?"
send "204.208.204.209\r"
expect "Source filename []?"
send "c3750-ipservicesk9-mz.122-55.SE7.bin\r"
expect "Destination filename"
send "\r"
expect {
-re {\mtimed out\M} {
send "copy tftp: flash:\r"
expect "Address or name of remote host []?"
send "XXX.XXX.XXX.XXX\r"
expect "Source filename []?"
send "c3750-ipservicesk9-mz.122-55.SE7.bin\r"
expect "Destination filename [c3750-ipservicesk9-mz.122-55.SE7.bin]?"
send "\r"
expect "*#"
}
-re {\mOK - 13010154 bytes\M}
}
# checks to see if there are other members in the stack, and if there are it will copy the ios from flash1 to the other devices.
send "dir ?\r"
expect {
-re {\mflash\M} {
send "\r"
expect "*#"
}
-re {\mflash1\M} {
send "\r"
expect "*#"
}
-re {\mflash2\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash2:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
-re {\mflash3\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash3:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
-re {\mflash4\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash4:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
-re {\mflash5\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash5:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
-re {\mflash6\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash6:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
-re {\mflash7\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash7:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
-re {\mflash8\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash8:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
-re {\mflash9\M} {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash9:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
}
Here is the output from the script when I pipe it to a file... I'm only capturing the first loop.
send: sending "dir ?\r" to { exp7 }
Gate keeper glob pattern for '\m(flash[1-9])\M' is 'flash?'. Activating booster.
expect: does "\r\n 6 -rwx 28612 Apr 23 2012 02:35:18 +02:00 config.text.backup\r\n 5 -rwx 1276 Mar 1 1993 01:04:41 +01:00 vlan.dat\r\n 4 -rwx 2404 Jun 17 2013 14:01:30 +02:00 private-config.text\r\n 88 -rwx 2404 Apr 23 2012 02:35:18 +02:00 private-config.text.backup\r\n 8 -rwx 43535 Jun 17 2013 14:01:29 +02:00 config.text\r\n\r\n32514048 bytes total (19417088 bytes free)\r\nB3762_6D205C_SW1&2#" (spawn_id exp7) match regular expression "\m(flash[1-9])\M"? Gate "flash?"? gate=no
"*#"? yes
expect: set expect_out(0,string) "\r\n 6 -rwx 28612 Apr 23 2012 02:35:18 +02:00 config.text.backup\r\n 5 -rwx 1276 Mar 1 1993 01:04:41 +01:00 vlan.dat\r\n 4 -rwx 2404 Jun 17 2013 14:01:30 +02:00 private-config.text\r\n 88 -rwx 2404 Apr 23 2012 02:35:18 +02:00 private-config.text.backup\r\n 8 -rwx 43535 Jun 17 2013 14:01:29 +02:00 config.text\r\n\r\n32514048 bytes total (19417088 bytes free)\r\nB3762_6D205C_SW1&2#"
expect: set expect_out(spawn_id) "exp7"
expect: set expect_out(buffer) "\r\n 6 -rwx 28612 Apr 23 2012 02:35:18 +02:00 config.text.backup\r\n 5 -rwx 1276 Mar 1 1993 01:04:41 +01:00 vlan.dat\r\n 4 -rwx 2404 Jun 17 2013 14:01:30 +02:00 private-config.text\r\n 88 -rwx 2404 Apr 23 2012 02:35:18 +02:00 private-config.text.backup\r\n 8 -rwx 43535 Jun 17 2013 14:01:29 +02:00 config.text\r\n\r\n32514048 bytes total (19417088 bytes free)\r\nB3762_6D205C_SW1&2#"
send: sending "copy tftp: flash:\r" to { exp7 }
expect: does "" (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
d
expect: does "d" (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
i
expect: does "di" (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
r
expect: does "dir" (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
expect: does "dir " (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
?
expect: does "dir ?" (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
/all List all files
/recursive List files recursively
all-filesystems List files on all filesystems
bs: Directory or file name
cns: Directory or file name
flash1: Directory or file name
flash2: Directory or file name
flash: Directory or file name
null: Directory or file name
nvram: Directory or file name
system: Directory or file name
tar: Directory or file name
tmpsys: Directory or file name
vb: Directory or file name
xmodem: Directory or file name
ymodem: Directory or file name
<cr>
B3762_6D205C_SW1&2#dir
expect: does "dir ?\r\n /all List all files\r\n /recursive List files recursively\r\n all-filesystems List files on all filesystems\r\n bs: Directory or file name\r\n cns: Directory or file name\r\n flash1: Directory or file name\r\n flash2: Directory or file name\r\n flash: Directory or file name\r\n null: Directory or file name\r\n nvram: Directory or file name\r\n system: Directory or file name\r\n tar: Directory or file name\r\n tmpsys: Directory or file name\r\n vb: Directory or file name\r\n xmodem: Directory or file name\r\n ymodem: Directory or file name\r\n <cr>\r\n\r\nB3762_6D205C_SW1&2#dir " (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
expect: does "dir ?\r\n /all List all files\r\n /recursive List files recursively\r\n all-filesystems List files on all filesystems\r\n bs: Directory or file name\r\n cns: Directory or file name\r\n flash1: Directory or file name\r\n flash2: Directory or file name\r\n flash: Directory or file name\r\n null: Directory or file name\r\n nvram: Directory or file name\r\n system: Directory or file name\r\n tar: Directory or file name\r\n tmpsys: Directory or file name\r\n vb: Directory or file name\r\n xmodem: Directory or file name\r\n ymodem: Directory or file name\r\n <cr>\r\n\r\nB3762_6D205C_SW1&2#dir \r\n" (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
Directory of flash:/
2 -rwx 9240 Jun 17 2013 14:01:30 +02:00 multiple-fs
3 -rwx 13006601 Apr 24 2012 19:24:08 +02:00 c3750-ipservicesk9-mz.122-55.SE5.bin
6 -rwx 28612 Apr 23 2012 02:35:18 +02:00 config.text.backup
5 -rwx 1276 Mar 1 1993 01:04:41 +01:00 vlan.dat
4 -rwx 2404 Jun 17 2013 14:01:30 +02:00 private-config.text
88 -rwx 2404 Apr 23 2012 02:35:18 +02:00 private-config.text.backup
8 -rwx 43535 Jun 17 2013 14:01:29 +02:00 config.text
32514048 bytes total (19417088 bytes free)
B3762_6D205C_SW1&2#
expect: does "dir ?\r\n /all List all files\r\n /recursive List files recursively\r\n all-filesystems List files on all filesystems\r\n bs: Directory or file name\r\n cns: Directory or file name\r\n flash1: Directory or file name\r\n flash2: Directory or file name\r\n flash: Directory or file name\r\n null: Directory or file name\r\n nvram: Directory or file name\r\n system: Directory or file name\r\n tar: Directory or file name\r\n tmpsys: Directory or file name\r\n vb: Directory or file name\r\n xmodem: Directory or file name\r\n ymodem: Directory or file name\r\n <cr>\r\n\r\nB3762_6D205C_SW1&2#dir \r\nDirectory of flash:/\r\n\r\n 2 -rwx 9240 Jun 17 2013 14:01:30 +02:00 multiple-fs\r\n 3 -rwx 13006601 Apr 24 2012 19:24:08 +02:00 c3750-ipservicesk9-mz.122-55.SE5.bin\r\n 6 -rwx 28612 Apr 23 2012 02:35:18 +02:00 config.text.backup\r\n 5 -rwx 1276 Mar 1 1993 01:04:41 +01:00 vlan.dat\r\n 4 -rwx 2404 Jun 17 2013 14:01:30 +02:00 private-config.text\r\n 88 -rwx 2404 Apr 23 2012 02:35:18 +02:00 private-config.text.backup\r\n 8 -rwx 43535 Jun 17 2013 14:01:29 +02:00 config.text\r\n\r\n32514048 bytes total (19417088 bytes free)\r\nB3762_6D205C_SW1&2#" (spawn_id exp7) match glob pattern "Address or name of remote host ?"? no
c
Here's an example of what it would look like if I ran all of those commands manually.
B3762_6D205C_SW1&2#term length 0
B3762_6D205C_SW1&2#wr
Building configuration...
[OK]
B3762_6D205C_SW1&2#dir flash:
# This first DIR tells me whether or not I have .bin version 5 or version 7. If I have version 7 I exit out of the script and I move on to upgrading another device. If it has version 5 continue on through the script.
Directory of flash:/
3 -rwx 13006601 Apr 24 2012 19:24:08 +02:00 c3750-ipservicesk9-mz.122-55.SE5.bin
6 -rwx 28612 Apr 23 2012 02:35:18 +02:00 config.text.backup
5 -rwx 1276 Mar 1 1993 01:04:41 +01:00 vlan.dat
4 -rwx 9240 Jun 18 2013 07:44:01 +02:00 multiple-fs
7 -rwx 43535 Jun 18 2013 07:44:01 +02:00 config.text
88 -rwx 2404 Apr 23 2012 02:35:18 +02:00 private-config.text.backup
8 -rwx 2404 Jun 18 2013 07:44:01 +02:00 private-config.text
32514048 bytes total (19417088 bytes free)
# This dir tells me how many flash file systems there are. I want to use this output to determine how many flash file systems I have to delete the old version 5 .bin file from.
B3762_6D205C_SW1&2#dir ?
/all List all files
/recursive List files recursively
all-filesystems List files on all filesystems
bs: Directory or file name
cns: Directory or file name
flash1: Directory or file name
flash2: Directory or file name
flash: Directory or file name
null: Directory or file name
nvram: Directory or file name
system: Directory or file name
tar: Directory or file name
tmpsys: Directory or file name
vb: Directory or file name
xmodem: Directory or file name
ymodem: Directory or file name
<cr>
B3762_6D205C_SW1&2#delete /force /recursive flash1:c3750-ipservicesk9-mz.122-55.SE5.bin
B3762_6D205C_SW1&2#delete /force /recursive flash2:c3750-ipservicesk9-mz.122-55.SE5.bin
B3762_6D205C_SW1&2#copy tftp: flash:
Address or name of remote host []? 204.208.204.209
Source filename []? c3750-ipservicesk9-mz.122-55.SE7.bin
Destination filename [c3750-ipservicesk9-mz.122-55.SE7.bin]?
Accessing tftp://204.208.204.209/c3750-ipservicesk9-mz.122-55.SE7.bin...
Loading c3750-ipservicesk9-mz.122-55.SE7.bin from 204.208.204.209 (via Vlan402): !OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!OO!O!OO!OO!OO!OOO!OO!OO!OO!OO!OO!OO!O!OO!OO!OO!OO!OO!OO!OO!OO
[OK - 13010154 bytes]
13010154 bytes copied in 281.312 secs (46248 bytes/sec)
B3762_6D205C_SW1&2#dir ?
# I want to use this "dir ?" to tell me I how many flash file systems I have to copy the new version 7 flash file system to.
/all List all files
/recursive List files recursively
all-filesystems List files on all filesystems
bs: Directory or file name
cns: Directory or file name
flash1: Directory or file name
flash2: Directory or file name
flash: Directory or file name
null: Directory or file name
nvram: Directory or file name
system: Directory or file name
tar: Directory or file name
tmpsys: Directory or file name
vb: Directory or file name
xmodem: Directory or file name
ymodem: Directory or file name
<cr>
B3762_6D205C_SW1&2#copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin flash2:
Destination filename [c3750-ipservicesk9-mz.122-55.SE7.bin]?
Copy in progress...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
13010154 bytes copied in 171.731 secs (75759 bytes/sec)
B3762_6D205C_SW1&2#conf t
Enter configuration commands, one per line. End with CNTL/Z.
B3762_6D205C_SW1&2(config)#boot system switch all flash:c3750-ipservicesk9-mz.122-55.SE7.bin
B3762_6D205C_SW1&2(config)#exit
B3762_6D205C_SW1&2#reload at 02:00 22 June
System configuration has been modified. Save? [yes/no]: yes
Building configuration...
[OK]
Reload scheduled for 02:00:00 CEST Sat Jun 22 2013 (in 90 hours and 3 minutes) by super.poop on vty0 (204.208.XXX.XXX)
Proceed with reload? [confirm]
B3762_6D205C_SW1&2#term length 50
B3762_6D205C_SW1&2#wr mem
Building configuration...
[OK]
B3762_6D205C_SW1&2#exit
This is the only section that's failing right now!
set DIR {flash2 flash3 flash4 flash5 flash6 flash7 flash8 flash9}
send "dir ?\r"
expect {
-re {\m(flash[2-9])\M} {
lappend DIR $expect_out(1,string)
exp_continue
}
"*#"
}
foreach X $DIR {
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin $X:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
I would say:
set flash_dirs {}
send "dir ?\r"
expect {
-re {\m(flash[1-9])\M} {
lappend flash_dirs $expect_out(1,string)
exp_continue
}
"*#"
}
foreach dir $flash_dirs {
send "delete /force /recursive $dir:c3750-ipservicesk9-mz.122-55.SE5\r"
expect "*#"
send "delete /force /recursive $dir:c3750-ipservicesk9-mz.122-55.SE5.bin\r"
expect "*#"
}
Then you copy stuff into flash1. After that, I assume the dir list has not changed, so you already know which flash drives are mounted:
foreach dir $flash_dirs {
if {$dir eq "flash1"} continue
send "copy flash1:c3750-ipservicesk9-mz.122-55.SE7.bin $dir:\r"
expect "Destination filename"
send "\r"
expect "*#"
}
Much DRYer. Untested of course.

Expect Output inconsistency

I want to automate the following interaction using Tcl/expect
[root#mgmt NAS]# ssh -q -p 8022 -l user 10.1.1.1
Password:
HP Network Automation Version 9.10.02
Type "HELP connect" to see how to connect to a device.
Type "HELP" to view a list of available commands.
NA>connect 10.1.1.2
WARNING: You do not have an approved reservation for this device at this time.
Attempting to connect to device bigip1.network.company.net (10.1.1.2).
Last login: Wed Sep 26 08:11:42 2012 from 10.2.1.1
Last login: Wed Sep 26 08:11:42 2012 from 10.2.1.1
[root#bigip1:Standby] config #
[root#bigip1:Standby] config #
[root#bigip1:Standby] config #
[root#bigip1:Standby] config # uname -a
Linux bigip1.network.company.net 2.6.18-164.11.1.el5.1.0.f5app #1 SMP Thu Apr 8 18:26:58 PDT 2010 i686 i686 i386 GNU/Linux
[root#bigip1:Standby] config # exit
logout
Disconnected from device bigip1.network.company.net (10.1.1.2).
NA>quit
Logging out of the NA Proxy Interface.
<Blank Line: couldn't show it with simple formatting>
The user input is essentially:
password
connect 10.1.1.2
uname -a
exit
quit
The script I wrote out, connect.exp, is as follows:
#!/usr/local/bin/expect
# Set the input parameters
set nashost [lindex $argv 0]
set port [lindex $argv 1]
set user [lindex $argv 2]
set passw [lindex $argv 3]
set device [lindex $argv 4]
set cmd [lindex $argv 5]
set binpath /usr/bin
log_user 0
# Set timeout to 45 seconds
set timeout 45
#check if all were provided
if { $nashost == "" || $port == "" || $user == "" || $passw == "" || $device == "" || $cmd == "" } {
puts "Usage: <nashost> <port> <user> <passw> <device> <command>\n"
exit 1
}
# String Variables
set nasprompt "NA>$"
set prompt "config # $"
# Flag Variables
set running 1
set count 0
# SSH to specified NAS host
if { [catch {spawn $binpath/ssh -q -p $port -o "StrictHostKeyChecking no" -l $user $nashost} error] } {
puts "Spawn: SSH failed: $error"
exit
}
expect {
"assword: " {
send "$passw\r"
incr count
if {$count > 3} {
puts "SSH failed on authentication after 3 tries"
set running 0
} else {
exp_continue
}
}
-re "$nasprompt" {
set running 1
}
"Connection refused" {
puts "$expect_out(buffer)"
set running 0
}
"Offending key" {
puts "Host key verification failed."
set running 0
}
eof {
puts -nonewline "Connection terminated unexpectedly:\n$expect_out(buffer)"
set running 0
}
timeout {
puts "ssh: connect to NAS host $host: Connection timed out"
set running 0
}
}
if {$running == 1} {
send "connect $device\r"
expect {
-re "$nasprompt" {
if {$running > 0} {
puts "connect to Device $device failed:\n$expect_out(buffer)"
}
send "quit\r"
}
-re "$prompt" {
if {$running > 0} {
send "$cmd\r"
set running 0
exp_continue
} else {
puts "$expect_out(buffer)"
send "exit\r"
}
}
full_buffer {
puts "$expect_out(buffer)"
exp_continue
}
eof {
puts "ssh: Connection terminated unexpectedly during command execution: $host."
}
timeout {
puts "ssh: Connection timed out during command execution: $host."
}
}
}
The issue I face is that the output I get for this interaction with this script is inconsistent.
I call the script as follows: expect connect.exp 10.1.1.1 8022 user 'pwd' 10.1.1.2 'uname -a'
Output one:
[root#bigip1:Standby] config #
[root#bigip1:Standby] config # uname -a
Linux bigip1.network.company.net 2.6.18-164.11.1.el5.1.0.f5app #1 SMP Thu Apr 8 18:26:58 PDT 2010 i686 i686 i386 GNU/Linux
[root#bigip1:Standby] config #
Output two:
<blank line>
<blank line>
u[root#bigip1:Standby] config #
[root#bigip1:Standby] config #
The u at the beginning of line 3 is part of the output, not a typo.
Other variations of output two exist as well.
The output I expected is:
Linux bigip1.network.company.net 2.6.18-164.11.1.el5.1.0.f5app #1 SMP Thu Apr 8 18:26:58 PDT 2010 i686 i686 i386 GNU/Linux
[root#bigip1:Standby] config #
What am I doing incorrect in my script?
After you send the password, you don't actually wait for the NA prompt before sending the connect command. Change your first expect command to:
set running false
expect {
"assword: " {
incr count
if {$count > 3} {
puts "SSH failed on authentication after 3 tries"
} else {
send "$passw\r"
exp_continue
}
}
"Connection refused" {
puts "$expect_out(buffer)"
}
"Offending key" {
puts "Host key verification failed."
}
eof {
puts -nonewline "Connection terminated unexpectedly:\n$expect_out(buffer)"
}
timeout {
puts "ssh: connect to NAS host $host: Connection timed out"
}
-re "$nasprompt" {
set running true
}
}
if {$running} {
send "connect ...