Training, Open Source computer languages
PerlPHPPythonMySQLApache / TomcatTclRubyJavaC and C++LinuxCSS 
Search for:
Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
 
For 2021 - online Python 3 training - see ((here)).

Our plans were to retire in summer 2020 and see the world, but Coronavirus has lead us into a lot of lockdown programming in Python 3 and PHP 7.
We can now offer tailored online training - small groups, real tutors - works really well for groups of 4 to 14 delegates. Anywhere in the world; course language English.

Please ask about private 'maintenance' training for Python 2, Tcl, Perl, PHP, Lua, etc.
global array not available in loop??

Posted by g00se (g00se), 28 July 2006
I'm using a global array inside a proc.  It is readable inside the proc (even when called multiple separate times), however at the end of my loop, I want to do something with the value in the array and it complains that there is nothing in the array element when I know there should be.

So I'm trying to store the current spawn_id in a global array called curr_spawn() every time I call the conn_telnet proc, so when I'm done I can gracefully exit from that particular "hop".  The problem is that I can't seem to read the value of the array curr_spawn() when I'm outside of the proc.  I think I took steps to make it available outside the proc so I don't understand why it isn't available??

If anyone has some time, can you please take a quick look and tell me what I'm doing wrong?  It's frustrating me!  Once I get this working, I can start working on compacting the code and making it a bit smarter.  But first I want to get it working  

Thanks in advance for any help!

Here's a copy of the relevant portions of the expect script:

*** START OF CODE ***
#!/usr/local/bin/expect

set timeout 30
set argc [llength $argv]
set filename [lindex $argv 0]
set prompt "(#|->|\\\$) $"
set iteration 0
global iteration 0
global curr_spawn()

if { $argc < 1} {
       send_user "\nPlease specify an input file.\n"
       exit
}

proc conn_telnet {a b c} {
       # a = host
       # b = uss_pass
       # c = prompt
       #
       # return codes:
       # 0 = success
       # 1 = telnet not enabled on this host
       # 2 = unable to find server in DNS
       # 3 = connect timeout
       # 4 = invalid uss account password
       # 5 = unknown error

       spawn telnet $a
       puts "spawn_id = $spawn_id"
       global iteration
       global curr_spawn()
       set curr_spawn(iteration) "$spawn_id"
       puts "\n\niteration = $iteration"      
       puts "curr_spawn(iteration) = $curr_spawn(iteration)\n\n"

       expect {
               "login:" {}

               "refused" { return 1 }

               "name not known" { return 2 }

               timeout { return 3 }
       }
       send "uss\r"
       expect "Password:"
       send "$b\r"
       expect {
               "login: $"      { return 4 }

               "> "    { send "e\r"
                       expect -re $c
                       return 0 }
               
               -re $c  { return 0 }
       }
       return 5
}

# main program
stty -echo
send_user "\nEnter current uss account password: "
expect_user {
       timeout {
               send_user "\nTimeout- please restart.\n"
               exit
       } -re "(.*)\n" {
               set uss_pass $expect_out(1,string)
       }
}

set count 1
set file [open $filename r]

foreach inputLine [split [read $file] "\n"] {
       if { $inputLine == "" } { puts "\nno more hosts to process."
       exit }

       set numExits 1
       set exitsDone 0

       #log_user 0
       set line [split $inputLine ":"]
       set numHops [llength $line]

       # don't count the host we're trying to connect to
       # as a "hop"
       incr numHops -1

       if { $numHops > 0 } {
               switch -- $numHops \
               1 {     set mainHost [lindex $line 0]
                       set hostLine [split $mainHost "|"]
                       set hostMethod [lindex $hostLine 0]
                       set host [lindex $hostLine 1]

                       set hop1 [lindex $line 1]
                       set hop1Line [split $hop1 "|"]
                       set hop1Method [lindex $hop1Line 0]
                       set hop1Host [lindex $hop1Line 1]

                       send_user "\n\[$host\]: "

                       # connect to the first hop.
                       if { $hop1Method == "S" } {
                               set retval [ conn_ssh $hop1Host $uss_pass $prompt ]
                               if { $retval > 0 } {
                                       puts "ERROR: Return code $retval."
                                       continue }
                       } else {
                               set retval [ conn_telnet $hop1Host $uss_pass $prompt ]
                               if { $retval > 0 } {
                                       puts "ERROR: Return code $retval."
                                       continue }
                       }
                       incr iteration +1

                       # we're connected to the first hop.  Now let's connect
                       # to the main host
                       if { $hostMethod == "S" } {
                               set retval [ conn_ssh $host $uss_pass $prompt ]
                               if { $retval > 0 } {
                                       puts "ERROR: Return code $retval."
                                       continue }
                       } else {
                               set retval [ conn_telnet $host $uss_pass $prompt ]
                               if { $retval > 0 } {
                                       puts "ERROR: Return code $retval."
                                       continue }
                       }

                       # need to send more exits to back all the way out gracefully.
                       # Gosh, we're nice aren't we
                       incr numExits +1
[....]
removed similar code for additional hops for berevity
[....]

               } default { puts "numHops = $numHops.  only able to handle 3 hops.  Find a DMZ server!!!"
               }

       } else {
               # we can get directly to the host without hopping around
               # like a damn bunny through the network.

               set hostLine [split $line "|"]
               set hostMethod [lindex $hostLine 0]
               set host [lindex $hostLine 1]

               send_user "\n\[$host\]: "

               if { $hostMethod == "S" } {
                       set retval [ conn_ssh $host $uss_pass $prompt ]
                       if { $retval > 0 } {
                               puts "ERROR: Return code $retval."
                               continue }
               } else {
                       set retval [ conn_telnet $host $uss_pass $prompt ]
                       if { $retval > 0 } {
                               puts "ERROR: Return code $retval."
                               continue }
               }
       }
       # need to set spawn_id to match what it was when we called the telnet
       # or ssh proc to connect to the box.  Don't quite know why this is
       # important, but hey- I'm still learning

       puts "iteration = $iteration"
       puts "curr_spawn(0) = $curr_spawn(0)"
       puts "curr_spawn(1) = $curr_spawn(1)"
       set spawn_id $curr_spawn(iteration)

       # do your stuff, tough guy
       #log_user 1
       send "uname -a\r"
       expect -re $prompt
       incr count +1
       #log_user 0

       # let's close the connections gracefully.  How nice of us...
       while { $exitsDone < $numExits } {
               set spawn_id $curr_spawn(iteration)
               puts "iteration = $iteration"
               send "exit\r"
               expect -re $prompt
               incr exitsDone +1
               incr iteration -1
       }
}

*** END OF CODE ***

Posted by admin (Graham Ellis), 29 July 2006
global curr_spawn() in your proc shoule read global curr_spawn.  The way you have written it the variable called curr_spawn is not global within the proc, but a variable with the strange name curr_spawn() is.

(and there's no need to declare a variable global in the main code - global means share this variable with the main code).


Try

Code:
proc xyz "" {
       global aaa
       set aaa(1) 33
       }

set aaa(1) 20
set aaa(2) 40
xyz
puts $aaa(1)
puts $aaa(2)


which prints out 33 ad 40. Add () after the global aaa statement and you get 20 and 40 printed.

I understand your desire to get your code working before you compact it. However, it's often much better practise to do so earlier, as it would make it mush easier for you to spot little codeing things like this, and it would make it much easier on anyone trying to help.   Frankly, I'm filled with dread when I see an example that's over a page long posted and I know it's going to take me a while to spot a tiny issue that the poster could have found just by reducing the code down to show the issue in less than 30  lines as requested in Opentalk's FAQ

Posted by g00se (g00se), 31 July 2006
Graham,

Thank you for responding.  I apologize for the lengthy code post (I'll familiarize myself with the FAQ section).  I guess it was more out of frustration at not understanding how tcl handles arrays and variables in general.  I'm used to declaring a variable as global at the main code level so the proc's can see them, not the other way around.  I guess I need to get a different book (Exploring expect doesn't seem to have the level of detail I need).  Do you have any recommendations?

Posted by admin (Graham Ellis), 1 August 2006
On the Tcl side of things, the book I would personally suggest for filling you in on how things work together is Practical Programming in Tcl and Tk.  On Expect, Don Libes' book that you've already mentioned contains all the facts, but little elaboration in some techniques.   Perhaps there's another book to be written there, or perhaps that extra topic is too niche!



This page is a thread posted to the opentalk forum at www.opentalk.org.uk and archived here for reference. To jump to the archive index please follow this link.

You can Add a comment or ranking to this page

© WELL HOUSE CONSULTANTS LTD., 2022: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho