Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Rewrite the expect telnet script in a more compact way.

520 views
Skip to first unread message

Hongyi Zhao

unread,
Jan 13, 2021, 10:10:22 PM1/13/21
to
Currently, I've written the following expect telnet script for router management:

---
set ip 192.168.1.1
set username root
set password Zte521
set timeout 10

spawn telnet $ip
expect -re ".?ogin: "
send "$username\r"
expect -re ".?assword: "
send "$password\r"


send "sendcmd 1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1\r"
send "sendcmd 1 DB set PortControl 3 PortEnable 1\r"
send "sendcmd 1 DB set TelnetCfg 0 TS_Enable 1\r"
send "sendcmd 1 DB set TelnetCfg 0 Lan_Enable 1\r"
send "sendcmd 1 DB save\r"
send "reboot\r"
expect eof
---

I try to re-write it with a more compact form as shown below:

---
set ip 192.168.1.1
set username root
set password Zte521
set timeout 10

set prompt "(%|#|>|\\$ )"
set prompt [string trim $prompt]

spawn telnet $ip

expect {
-re ".?ogin: " { send "$username\r"; exp_continue }
-re ".?assword: " { send "$password\r"; exp_continue }
-re $prompt {
send "sendcmd 1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1\r"
send "sendcmd 1 DB set PortControl 3 PortEnable 1\r"
send "sendcmd 1 DB set TelnetCfg 0 TS_Enable 1\r"
send "sendcmd 1 DB set TelnetCfg 0 Lan_Enable 1\r"
send "sendcmd 1 DB save\r"
send "reboot\r"
eof
}
}
---

I'm a newbie of TCL language, and not sure if the rewritten version is correct. Any hints/notes/suggestions/comments/fixes/corrections/touch ups/enhancements are highly appreciated.

Regards,
HY

Uwe Klein

unread,
Jan 14, 2021, 3:33:55 AM1/14/21
to
Am 14.01.21 um 04:10 schrieb Hongyi Zhao:
I'd expect "timeout" ( with an error message ) too as a diagnostic.

Uwe

heinrichmartin

unread,
Jan 14, 2021, 3:41:20 AM1/14/21
to
On Thursday, January 14, 2021 at 4:10:22 AM UTC+1, HY wrote:
> spawn telnet $ip
> expect -re ".?ogin: "
> send "$username\r"
> expect -re ".?assword: "
> send "$password\r"

From man expect: "The -nocase flag causes uppercase characters of the output to compare as if they were lowercase characters. The pattern is not affected."
In real world examples the .? of the regex is useless (matching is unanchored), and I prefer patterns as strict as possible (fail fast).

> send "sendcmd 1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1\r"
> send "sendcmd 1 DB set PortControl 3 PortEnable 1\r"
> send "sendcmd 1 DB set TelnetCfg 0 TS_Enable 1\r"
> send "sendcmd 1 DB set TelnetCfg 0 Lan_Enable 1\r"
> send "sendcmd 1 DB save\r"
> send "reboot\r"
> expect eof

I'd wait for a prompt before issuing new commands; well, if it works and stability is not a strict requirement, it will probably work.

> I try to re-write it with a more compact form as shown below:

> set prompt "(%|#|>|\\$ )"
> set prompt [string trim $prompt]

There are cases where calculating a constant improves readability, but this does not seem to be the case here.
It does not look like you require the reporting group ().
In Tcl, I use braces for regex.

> expect {
> -re ".?ogin: " { send "$username\r"; exp_continue }
> -re ".?assword: " { send "$password\r"; exp_continue }

Does none of the below commands' output match these?

> -re $prompt {
> send "sendcmd 1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1\r"
> send "sendcmd 1 DB set PortControl 3 PortEnable 1\r"
> send "sendcmd 1 DB set TelnetCfg 0 TS_Enable 1\r"
> send "sendcmd 1 DB set TelnetCfg 0 Lan_Enable 1\r"
> send "sendcmd 1 DB save\r"
> send "reboot\r"

You are probably missing exp_continue here. And you should swap the below lines. eof is a new pattern, not a command in this code block.

> eof
> }
> }
> ---
>
> I'm a newbie of TCL language, and not sure if the rewritten version is correct. Any hints/notes/suggestions/comments/fixes/corrections/touch ups/enhancements are highly appreciated.

I'd probably separate the login from the rest. On a green-field setting, I'd turn off tty echo (stty -echo).

You could have the commands in a list and process them in a loop.

# untested
# this is also a demo of a few useful/fun commands ;-)
set sendcmds {
# do A
1 DB set A
# do B
1 DB set B
# ...
}
set sendcmds [lmap l [split [string trim $sendcmds] \n] {
if {[regexp {^\s*#} $l} continue
string trim $l
}]

# you could move the lmap code to this loop, too
foreach sendcmd $sendcmds {
expect {
-re $prompt {
exp_send "sendcmd $sendcmd\r"
}
}
}

# finally reboot

# alternatively using exp_continue
# no foreach here!
expect {
-re $prompt {
set sendcmds [lassign $sendcmds sendcmd]
exp_send ...
if {[llength $sendcmds]} exp_continue
}
}

HTH
Martin

heinrichmartin

unread,
Jan 14, 2021, 3:46:39 AM1/14/21
to
On Thursday, January 14, 2021 at 9:41:20 AM UTC+1, heinrichmartin wrote:
> set sendcmds [lmap l [split [string trim $sendcmds] \n] {
> if {[regexp {^\s*#} $l} continue
> string trim $l
> }]

I missed two close brackets here (if I counted correctly). Sorry, it was not by intention. Find the right spot to improve your Tcl skills ;-)

Hongyi Zhao

unread,
Jan 14, 2021, 11:04:37 AM1/14/21
to
To be frank, finding and fixing this sort of error manually is indeed a tedious and
laborious job. I try to use the power of Emacs to find the right spot and fix the
problem quickly for this scenario. There seems to be a powerful package designed for this kind of work, see <https://github.com/Fuco1/smartparens> for more detailed info. But I am learning how to use that package correctly ;-)

Best,
HY

heinrichmartin

unread,
Jan 14, 2021, 3:02:45 PM1/14/21
to
But you tried :-) and even with automated checkers for balanced braces of any kind, you want to understand which argument and which commands end at which location.

1 was the regexp command inside if's expression.
2 was the lmap command that ends 3 lines below its open bracket (just after the close bracket of split).

Hongyi Zhao

unread,
Jan 14, 2021, 7:30:50 PM1/14/21
to
I still want to try out whether I can fix this sort of problems automatically with the power of elisp. See <https://github.com/Fuco1/smartparens/issues/1069#issuecomment-760465022> for the detailed context of the following notes given by the author of the smartparens package:


I don't know TCL so I don't know where the pair should be inserted. There is a feature which can insert missing brackets to preserve balance, but it simply works at point, there is no logic to understand the code. See command sp-up-sexp and setting sp-navigate-close-if-unbalanced.


I will further try to see the possibility of artificial intelligence code syntax error correction and automatic repair based on the power of lisp using smartparens package as follows:

M-x RET sp-up-sexp RET sp-navigate-close-if-unbalanced

Hongyi Zhao

unread,
Jan 15, 2021, 5:18:29 AM1/15/21
to
Indeed, you miss a close bracket here.

> 2 was the lmap command that ends 3 lines below its open bracket (just after the close bracket of split).

No, you don't miss any bracket/parenthese here.

See my following testing for more info:

$ cat lmap.tcl
#!/usr/bin/env expect

set sendcmds {
# do A
1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1
# do B
1 DB set PortControl 3 PortEnable 1
}

set sendcmds [lmap l [split [string trim $sendcmds] \n] {
if {[regexp {^\s*#} $l]} continue
string trim $l
}]

foreach i $sendcmds {
puts $i
;# do what ever with i
}
#puts $sendcmds

$ ./lmap.tcl
1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1
1 DB set PortControl 3 PortEnable 1

Best,
HY

ted brown

unread,
Jan 15, 2021, 10:28:05 AM1/15/21
to
Since tcl has lots of matching of brackety thingys of one kind or
another, a quite simple approach I use to keep it straight is that
whenever I am starting a {} () “ “ or [] group, I always type the pair
immediately, and hit a left arrow. Then I fill in the inside. And that
works recursively.

Lots easier than adding them all at the end, although I do have several
editor add-ins to do that, at least for on a single line. Going
backwards to find the match is tricky, since you need to consider \
escapes and quotes, but it’s doable. But if you know you're going to
need that closer, why not type it immediately, even if it's going to
wind up on another line.

For regular expressions, I use a paid tool on windows called regexbuddy.
Not only does it know every flavor of regex, it can even write a snippit
of code, including for tcl. There is also a site https://regex101.com/
to help with regex. These can make sure you got your bracketing
correctly matched.


Harald Oehlmann

unread,
Jan 15, 2021, 10:43:52 AM1/15/21
to

> Since tcl has lots of matching of brackety thingys of one kind or
> another, a quite simple approach I use to keep it straight is that
> whenever I am starting a {} () “ “ or []  group, I always type the pair
> immediately, and hit a left arrow. Then I fill in the inside. And that
> works recursively.

Are you aware of the tcl command "info complete", to check, if all
brackets etc are closed in a given code snippet ?

Thanks,
Harald

Hongyi Zhao

unread,
Jan 15, 2021, 10:54:16 AM1/15/21
to
Thanks a lot. I've successfully figured out the solution based on the above mentioned method:

--- begin ---
stty -echo
set ip 192.168.1.1
set username root
set password Zte521
set timeout 10

set prompt {[%#>$] }

spawn telnet $ip
expect -nocase "login: "
send "$username\r"
expect -nocase "password: "
send "$password\r"

set sendcmds {
1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1
1 DB set PortControl 3 PortEnable 1
1 DB set TelnetCfg 0 TS_Enable 1
1 DB set TelnetCfg 0 Lan_Enable 1
1 DB save
}

set sendcmds [
lmap l [split [string trim $sendcmds] \n] {
if {
[regexp {^\s*#} $l]
} continue
string trim $l
}
]

foreach sendcmd $sendcmds {
expect {
-re $prompt {
send "sendcmd $sendcmd\r"
}
}
}

# finally reboot
send "reboot\r"
expect eof
--- end ---

>
> # finally reboot
>
> # alternatively using exp_continue
> # no foreach here!
> expect {
> -re $prompt {
> set sendcmds [lassign $sendcmds sendcmd]
> exp_send ...
> if {[llength $sendcmds]} exp_continue
> }
> }

But I still can't succeed based on the above ideas. See the following codes used by me:

--- begin ---
[snip the same codes]
# alternatively using continue
# no foreach here!
expect {
-re $prompt {
set sendcmds [lassign $sendcmds sendcmd]
send "sendcmd $sendcmd\r"
if {[llength $sendcmds]} continue
}
}
[snip the same codes]
--- end ---


The error with the above method is shown below:

/ # invoked "continue" outside of a loop
while executing
"expect {
-re $prompt {
set sendcmds [lassign $sendcmds sendcmd]
send "sendcmd $sendcmd\r"
if {[llength $sendcmds]} { continue }
}
}"
(file "./tcl-telnet.tcl" line 57)


Any hints for solving this problem?

OTOH, I also tried to rewrite the login codes into the following:

expect {
-nocase "login: " {
send "$username\r"
}
-nocase "password: " {
send "$password\r"
}
}

But I always failed to login with the above revision version. Any hints for this problem?

Regards,
HY

Uwe Klein

unread,
Jan 15, 2021, 11:25:23 AM1/15/21
to
Am 15.01.21 um 16:54 schrieb Hongyi Zhao:
> OTOH, I also tried to rewrite the login codes into the following:
>
> expect {
> -nocase "login: " {
> send "$username\r"
exp_continue
> }
> -nocase "password: " {
> send "$password\r"
> }
> }
>
> But I always failed to login with the above revision version. Any hints for this problem?
>

after one of either path is hit you drop out of the expect call.

you either need to separate this into two calls to expect
or insert an exp_continue into the "login: " path
to catch the "password: " part of the dialog.

Uwe




ted brown

unread,
Jan 15, 2021, 12:00:49 PM1/15/21
to
Funny, I just found a use for [info complete] a week ago for a code
instrumentation use. But you’ve just given me a wacky idea.

Since there are really only the 4 “ } ] and ) to deal with, suppose I
brute force check all of the possibilities.

Let’s see, add 1 char 4 times, checking 4 times. If no success, add
another set of 4, sort of like an odometer for base four numbering. Keep
going say up to 8 or so. That would be what, 4^8’th checks? My amazon
echo just told me that’s about 65000 or so.

I wonder how fast [info complete] is?

ooooo, this sounds like fun. Or maybe that’s what you were hinting at.
I’ll be back to ya!

Thanks!

Rich

unread,
Jan 15, 2021, 12:07:00 PM1/15/21
to
ted brown <tedbr...@gmail.com> wrote:
> On 1/15/2021 7:43 AM, Harald Oehlmann wrote:
> Funny, I just found a use for [info complete] a week ago for a code
> instrumentation use. But you?ve just given me a wacky idea.
>
> Since there are really only the 4 ? } ] and ) to deal with, suppose
> I brute force check all of the possibilities.
>
> Let?s see, add 1 char 4 times, checking 4 times. If no success, add
> another set of 4, sort of like an odometer for base four numbering.
> Keep going say up to 8 or so. That would be what, 4^8?th checks? My
> amazon echo just told me that?s about 65000 or so.

You are likely designing an O(n^2) or worse (i.e., larger exponent)
complexity algorithm here. The runtime will likely explode for rather
small increases in the size of the input data.

> I wonder how fast [info complete] is?

Tcl provides a [time] command, so you can find out the answer to this
question.

ted brown

unread,
Jan 15, 2021, 12:23:53 PM1/15/21
to
Ah yes, but wouldn't it completely depend on how long the line is to the
left where I start the check. As a rough idea before even trying [time]
I would think it would be no worse than a 64k line script, and tcl is
pretty fast. I'm assuming [info check] runs though the regular tcl
parser code and is written in C code.

And if I find a success, I can quit early. Even if it takes a second or
two it'd be something done from a call to tcl from my text editor. Still
faster than doing it manually.

I could even check the time and after every N checks see how much time
I've spent and if it's 2 seconds or so, time to give up.

I once wrote my own spell checker based on hashing every word in a
dictionary. Then when I got a misspelling I had some 10 or 20
transformations, such as flipping every 2 letters, and would re-hash
looking for possibilities of correctly spelled words to give as
suggestions. That was a fun algorithm.

This sounds like one of those RS weekend projects from the wiki. Better
than watching TV :)




heinrichmartin

unread,
Jan 15, 2021, 2:40:08 PM1/15/21
to
On Friday, January 15, 2021 at 4:54:16 PM UTC+1, HY wrote:
> On Thursday, January 14, 2021 at 4:41:20 PM UTC+8, heinrichmartin wrote:
> > # alternatively using exp_continue
> > # no foreach here!
> > expect {
> > -re $prompt {
> > set sendcmds [lassign $sendcmds sendcmd]
> > exp_send ...
> > if {[llength $sendcmds]} exp_continue
> > }
> > }
> But I still can't succeed based on the above ideas. See the following codes used by me:
>
> --- begin ---
> [snip the same codes]
> # alternatively using continue
> # no foreach here!
> expect {
> -re $prompt {
> set sendcmds [lassign $sendcmds sendcmd]
> send "sendcmd $sendcmd\r"
> if {[llength $sendcmds]} continue
> }
> }
> [snip the same codes]
> --- end ---
>
>
> The error with the above method is shown below:
>
> / # invoked "continue" outside of a loop

continue is not exp_continue:

expect:~$ catch continue res opt; puts $opt
-code 4 -level 0
expect:~$ catch exp_continue res opt; puts $opt
-code -101 -level 0

i.e. expect has its custom return code for that case.
You were probably fooled by the fact that expect provides a send command but also exp_send (just in case send conflicts with another package).

Rich

unread,
Jan 15, 2021, 4:02:58 PM1/15/21
to
ted brown <tedbr...@gmail.com> wrote:
> On 1/15/2021 9:06 AM, Rich wrote:
>> ted brown <tedbr...@gmail.com> wrote:
>>> On 1/15/2021 7:43 AM, Harald Oehlmann wrote:
>>> Funny, I just found a use for [info complete] a week ago for a code
>>> instrumentation use. But you?ve just given me a wacky idea.
>>>
>>> Since there are really only the 4 ? } ] and ) to deal with, suppose
>>> I brute force check all of the possibilities.
>>>
>>> Let?s see, add 1 char 4 times, checking 4 times. If no success, add
>>> another set of 4, sort of like an odometer for base four numbering.
>>> Keep going say up to 8 or so. That would be what, 4^8?th checks? My
>>> amazon echo just told me that?s about 65000 or so.
>>
>> You are likely designing an O(n^2) or worse (i.e., larger exponent)
>> complexity algorithm here. The runtime will likely explode for rather
>> small increases in the size of the input data.
>>
>>> I wonder how fast [info complete] is?
>>
>> Tcl provides a [time] command, so you can find out the answer to this
>> question.
>>
>
> Ah yes, but wouldn't it completely depend on how long the line is to
> the left where I start the check.

Yes, but the part that is hard for humans (who inhabit a generally
linear existance) is just how rapidly the change happens.

With an O(n^2) complexity, the "effort" (and consequently the time)
goes up roughtly to the square of the input size.

So 10 items will take 100 units of effort.

But 100 items will take 10,000 units of effort.

And 1,000 items will take 1,000,000 units of effort.

And of course the increase is even faster if the exponent is larger
than 2.

> As a rough idea before even trying [time] I would think it would be
> no worse than a 64k line script, and tcl is pretty fast.

You'd have to give it a try, but you very well may find that the time
usage is very excessive well before you hit 64k lines.

ted brown

unread,
Jan 15, 2021, 7:57:24 PM1/15/21
to
On 1/15/2021 1:02 PM, Rich wrote:

> Yes, but the part that is hard for humans (who inhabit a generally
> linear existance) is just how rapidly the change happens.
>

You're right, the only B I got in my CS masters program at USC was in
analysis of algorithms. I wasn't good at theorem proof, the NP stuff
cost me a letter grade.

Yet tcl is soooo easy to do this sort of thing in, I think I'll take one
of my longer programs and run every line though it 10 times and use time
on the entire pass.

And if it's reasonable, maybe I'll take another look at threads, since
with only 4 chars to try, and me with a i7 4790k and 4 cores, it could
be an application made for threading. I'll have to read Ashok's thread
chapter again though.

You wouldn't happen to have a ready made thread example that would take
4 commands like that [info complete] and hand it off to 4 threads that
would then meet up when done with four 0/1 results?

BTW, are you a CS professor?

Hongyi Zhao

unread,
Jan 15, 2021, 10:09:38 PM1/15/21
to
Thanks a lot for pointing this out. It does the trick using the exp_continue command instead of the general tcl continue command for my case discussed here.

A few other questions I still can't figure out:

1. I've already use the following stty setting in my expect script:

stty -echo

But the expect script still will echo the results as shown below:

----
werner@X10DAi:~$ ./tcl-telnet.tcl
spawn telnet 192.168.1.1
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.
F612
Login: root
Password:

BusyBox v1.01 (2016.05.04-20:21+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

/ # sendcmd 1 DB set TelnetCfg 0 Lan_EnableAfterOlt 1
<Tbl name="TelnetCfg" RowCount="1">
<Row No="0">
<DM name="TS_Enable" val="1"/>
<DM name="Wan_Enable" val="0"/>
<DM name="Lan_Enable" val="1"/>
<DM name="TS_Port" val="23"/>
<DM name="TSLan_Port" val="23"/>
<DM name="TS_UName" val="root"/>
<DM name="TS_UPwd" val="Zte521"/>
<DM name="TSLan_UName" val="root"/>
<DM name="TSLan_UPwd" val="Zte521"/>
<DM name="Max_Con_Num" val="50"/>
<DM name="ProcType" val="0"/>
<DM name="Lan_EnableAfterOlt" val="1"/>
<DM name="TS_Sprtwl_Mode" val="0"/>
<DM name="WanWebLinkToTS" val="1"/>
</Row>
</Tbl>
----

2. I try to rewrite the reboot commands into the following:

expect {
eof { send "reboot\r" }
}


But I find that it won't reboot at all this way. Any hints for fixing this problem?

Regards,
HY

Hongyi Zhao

unread,
Jan 15, 2021, 10:11:31 PM1/15/21
to
Thanks a lot for pointing this out. It does the trick.

HY

Hongyi Zhao

unread,
Jan 16, 2021, 3:30:16 AM1/16/21
to
Based on your suggestions in another post <https://groups.google.com/g/comp.lang.tcl/c/ebngzYkvU6M>, I figured out the following codes which seems to solve the problem well:

---
expect {
-re $prompt {
send "reboot\r"
expect -timeout 5 eof {
# success
} -re {error: ([^\r\n]+)} {
# refine the re above to the modem's output!
puts stderr "The modem failed to reboot: $expect_out(1,string)"
} timeout {
puts stderr "The modem failed to reboot: timeout"
}
}
}
---

Regards,
HY

Uwe Klein

unread,
Jan 16, 2021, 4:42:56 AM1/16/21
to
Am 16.01.21 um 04:09 schrieb Hongyi Zhao:
stty -echo touches the spawned side and not
the script user side. ( ? )
unsurprising.

you expect the outcome (EOF) from sending "reboot"
before you send "reboot" :-)

you send "reboot" to the device
device goes into reboot and in the process takes down the connection
resulting in an EOF condition ..

you expect that EOF to flush out the connection on your side.
and thus finish your script.

Uwe


Hongyi Zhao

unread,
Jan 16, 2021, 5:41:57 AM1/16/21
to
What's the meaning of the question mark used here?
So, it's I that completely misunderstood the logical relationship for the job I want to do.

Regards,
HY

Uwe Klein

unread,
Jan 16, 2021, 6:45:30 AM1/16/21
to
Am 16.01.21 um 11:41 schrieb Hongyi Zhao:
>>> But I find that it won't reboot at all this way. Any hints for fixing this problem?
>> unsurprising.
>>
>> you expect the outcome (EOF) from sending "reboot"
>> before you send "reboot" :-)
>>
>> you send "reboot" to the device
>> device goes into reboot and in the process takes down the connection
>> resulting in an EOF condition ..
>>
>> you expect that EOF to flush out the connection on your side.
>> and thus finish your script.
>
> So, it's I that completely misunderstood the logical relationship for the job I want to do.
>
> Regards,
> HY
>

looks like :-)

your expect script starts with spawning/creating a socket connection to
your device.

login ...
couple of configuration commands ..
that done
you command a reboot.
in the process the "other" side closes down the socket connection.
your side ( the expect script ) realizes this only ever
when you expect (and consume) that EOF condition.
socket connection is now taken down on both sides.
your script is finished.

Uwe

Hongyi Zhao

unread,
Jan 16, 2021, 10:28:25 AM1/16/21
to
On Saturday, January 16, 2021 at 3:40:08 AM UTC+8, heinrichmartin wrote:
I inspected the corresponding documents for catch located at the following websites:

https://wiki.tcl-lang.org/page/catch
https://www.tcl-lang.org/man/tcl/TclCmd/catch.htm

But I can't find similar usages on these websites as you mentioned above. Could you please give me some hints/explanations on your above examples?

Rich

unread,
Jan 16, 2021, 3:54:39 PM1/16/21
to
ted brown <tedbr...@gmail.com> wrote:
> You wouldn't happen to have a ready made thread example that would
> take 4 commands like that [info complete] and hand it off to 4
> threads that would then meet up when done with four 0/1 results?

Look at the 'join' command in the thread package (and, of course, be
sure to launch the background threads as "joinable".

You can also use the tpool extension, and have the pool threads
"message" the master (thread::send) when they are done.

Do note that new threads startup with nothing in common to the thread
that started them (they start largely like brand new interpreters when
you launch a script). So you also have to "package require" (after any
appropriate auto_path and tcl::tm::path add adjustments) any
libraries/modules they will use, even if the launching thread has
already loaded the same.

> BTW, are you a CS professor?

Nope, EE. But I've been programming as a hobby since circa 1984.

heinrichmartin

unread,
Jan 17, 2021, 3:08:55 PM1/17/21
to
On Saturday, January 16, 2021 at 11:41:57 AM UTC+1, HY wrote:
> On Saturday, January 16, 2021 at 5:42:56 PM UTC+8, Uwe Klein wrote:
> > Am 16.01.21 um 04:09 schrieb Hongyi Zhao:
> > > On Saturday, January 16, 2021 at 3:40:08 AM UTC+8, heinrichmartin wrote:
> > >> On Friday, January 15, 2021 at 4:54:16 PM UTC+1, HY wrote:
> > > 1. I've already use the following stty setting in my expect script:
> > >
> > > stty -echo
> > >
> > > But the expect script still will echo the results as shown below:
> > stty -echo touches the spawned side and not
> > the script user side. ( ? )
> What's the meaning of the question mark used here?

TL;DR whether the conversation answered that.
stty -echo disables that the tty (~ the "console") shows your own keystrokes.
What you see is governed by log_user (iirc). You might want to have a look at exp_internal, too.

heinrichmartin

unread,
Jan 17, 2021, 3:39:50 PM1/17/21
to
On Saturday, January 16, 2021 at 4:28:25 PM UTC+1, HY wrote:
> On Saturday, January 16, 2021 at 3:40:08 AM UTC+8, heinrichmartin wrote:
> > continue is not exp_continue:
> >
> > expect:~$ catch continue res opt; puts $opt
> > -code 4 -level 0
> > expect:~$ catch exp_continue res opt; puts $opt
> > -code -101 -level 0
> I inspected the corresponding documents for catch located at the following websites:
>
> https://wiki.tcl-lang.org/page/catch
> https://www.tcl-lang.org/man/tcl/TclCmd/catch.htm
>
> But I can't find similar usages on these websites as you mentioned above. Could you please give me some hints/explanations on your above examples?

What part remained unclear?
* My script is a single word - I left out the usual braces.
* I am sending two commands at once in interactive mode to not show the return value of catch.
* Further details of Tcl's return structure can also be found on man return, not only catch.
* Expect's exp_continue is described on man expect.
HTH

Hongyi Zhao

unread,
Jan 17, 2021, 9:58:17 PM1/17/21
to
Thanks a lot for you notes. Based on you above hints, I found the
following related documentation description:

$ man expect | egrep -A 11 '^[ ]*exp_internal'
exp_internal [-f file] value
causes further commands to send diagnostic information
internal to Expect to stderr if
value is non-zero. This output is disabled if value is
0. The diagnostic information in‐
cludes every character received, and every attempt made
to match the current output
against the patterns.

If the optional file is supplied, all normal and
debugging output is written to that file
(regardless of the value of value). Any previous
diagnostic output file is closed.

The -info flag causes exp_internal to return a
description of the most recent non-info ar‐
guments given.


So, I figured out the following usage:

exp_internal -f debug_info.log 0

Best,
HY

Hongyi Zhao

unread,
Jan 17, 2021, 10:07:04 PM1/17/21
to
On Monday, January 18, 2021 at 4:39:50 AM UTC+8, heinrichmartin wrote:
> On Saturday, January 16, 2021 at 4:28:25 PM UTC+1, HY wrote:
> > On Saturday, January 16, 2021 at 3:40:08 AM UTC+8, heinrichmartin wrote:
> > > continue is not exp_continue:
> > >
> > > expect:~$ catch continue res opt; puts $opt
> > > -code 4 -level 0
> > > expect:~$ catch exp_continue res opt; puts $opt
> > > -code -101 -level 0
> > I inspected the corresponding documents for catch located at the following websites:
> >
> > https://wiki.tcl-lang.org/page/catch
> > https://www.tcl-lang.org/man/tcl/TclCmd/catch.htm
> >
> > But I can't find similar usages on these websites as you mentioned above. Could you please give me some hints/explanations on your above examples?
> What part remained unclear?

The most incomprehensible question for me is as follows:

In the command issued by you: "catch continue res opt", what's the meaning of *res* here? Why must you use it?

Rich

unread,
Jan 17, 2021, 10:15:31 PM1/17/21
to
Hongyi Zhao <hongy...@gmail.com> wrote:
> On Monday, January 18, 2021 at 4:39:50 AM UTC+8, heinrichmartin wrote:
>> On Saturday, January 16, 2021 at 4:28:25 PM UTC+1, HY wrote:
>> > On Saturday, January 16, 2021 at 3:40:08 AM UTC+8, heinrichmartin wrote:
>> > > expect:~$ catch exp_continue res opt; puts $opt
>> > I inspected the corresponding documents for catch located at the following websites:
>> >
>> > https://wiki.tcl-lang.org/page/catch
>> > https://www.tcl-lang.org/man/tcl/TclCmd/catch.htm
>>
>> What part remained unclear?
>
> The most incomprehensible question for me is as follows:
>
> In the command issued by you: "catch continue res opt", what's the
> meaning of *res* here? Why must you use it?

"catch" is a Tcl command that allows a script to handle error
conditions itself (instead of aborting). Look up the documentation of
the catch command (links to which was provided to you above) for what
the extra parameters mean.

Hongyi Zhao

unread,
Jan 18, 2021, 12:02:01 AM1/18/21
to
Based on the documentation as excerpted below:

catch script ?resultVarName? ?optionsVarName?

By comparison with the following command:

catch exp_continue res opt

So, it's obvious that:

res ---> resultVarName
opt ---> optionsVarName

And then based on the following notes given on
<https://www.tcl-lang.org/man/tcl/TclCmd/catch.htm>:

If the optionsVarName argument is given, then the variable it names is
set to a dictionary of return options returned by evaluation of
script. Tcl specifies two entries that are always defined in the
dictionary: -code and -level. When the return code from evaluation of
script is not TCL_RETURN, the value of the -level entry will be 0, and
the value of the -code entry will be the same as the return code.


So, the -level entry will be 0 for this case and the -code
corresponding to the return code as shown below:

expect1.7> catch exp_continue res opt; puts $opt
-code -101 -level 0
expect1.8> catch exp_continue res opt; put $opt
-code -101 -level 0

BTW, another question as shown above: what's the differences between
put and puts. As you can see, both can be used to write to stdout.

Thanks again for your valuable notes and suggestions.

Best regards,
HY

Rich

unread,
Jan 18, 2021, 12:32:44 AM1/18/21
to
Hongyi Zhao <hongy...@gmail.com> wrote:
> expect1.7> catch exp_continue res opt; puts $opt
> -code -101 -level 0
> expect1.8> catch exp_continue res opt; put $opt
> -code -101 -level 0
>
> BTW, another question as shown above: what's the differences between
> put and puts. As you can see, both can be used to write to stdout.

"puts" is the standard Tcl command to output data to a file descriptor.

"put" is not a standard Tcl command, so it must be defined elsewhere
within your script.

Hongyi Zhao

unread,
Jan 18, 2021, 12:52:10 AM1/18/21
to
To be frank, I just run the plain expect command shipped with the system's package installation. I myself don't define it all. So, what's the definition comes from?

js

unread,
Jan 18, 2021, 1:41:42 AM1/18/21
to
It is the interactive shell doing you a favor by expanding it put to
puts automatically. Try doing it by sourcing from a file and see what
happens.

Hongyi Zhao

unread,
Jan 18, 2021, 2:31:23 AM1/18/21
to
You're absolutely right. Confirmed what you told above. See following for detailed info:

werner@X10DAi:~$ cat 111.tcl
#!/usr/bin/env tclsh

put 'put'
werner@X10DAi:~$ ./111.tcl
invalid command name "put"
while executing
"put 'put'"
(file "./111.tcl" line 3)


Thanks again.

Best,
HY

heinrichmartin

unread,
Jan 18, 2021, 3:55:05 AM1/18/21
to
On Monday, January 18, 2021 at 8:31:23 AM UTC+1, HY wrote:
> On Monday, January 18, 2021 at 2:41:42 PM UTC+8, js wrote:
> > It is the interactive shell doing you a favor by expanding it put to
> > puts automatically. Try doing it by sourcing from a file and see what
> > happens.
> You're absolutely right. Confirmed what you told above. See following for detailed info:
>
> X10DAi:~$ cat 111.tcl
> #!/usr/bin/env tclsh
>
> put 'put'
> X10DAi:~$ ./111.tcl
> invalid command name "put"
> while executing
> "put 'put'"
> (file "./111.tcl" line 3)

The documentation is in man unknown: "[...] unknown checks to see if the command was invoked at top-level and outside of any script. If so, [...] unknown checks to see if cmd is a unique abbreviation for an existing Tcl command. If so, it expands the command name and executes the command with the original arguments." Note that I left out several steps while shortening!

And I prefer tab-completion (e.g. via tclreadline) over relying on unknown. Think of e.g. ll for llength - the behaviour depends on whether or not you have a shell alias ll (lor ls -l). To be clear, I like the unknown feature (for namespaces, ensembles, oo) for various use-cases, I just don't like second-guessing the user, which is a source of hidden errors and confusion.

Hongyi Zhao

unread,
Jan 18, 2021, 4:23:57 AM1/18/21
to
On Monday, January 18, 2021 at 4:55:05 PM UTC+8, heinrichmartin wrote:
> On Monday, January 18, 2021 at 8:31:23 AM UTC+1, HY wrote:
> > On Monday, January 18, 2021 at 2:41:42 PM UTC+8, js wrote:
> > > It is the interactive shell doing you a favor by expanding it put to
> > > puts automatically. Try doing it by sourcing from a file and see what
> > > happens.
> > You're absolutely right. Confirmed what you told above. See following for detailed info:
> >
> > X10DAi:~$ cat 111.tcl
> > #!/usr/bin/env tclsh
> >
> > put 'put'
> > X10DAi:~$ ./111.tcl
> > invalid command name "put"
> > while executing
> > "put 'put'"
> > (file "./111.tcl" line 3)
> The documentation is in man unknown:

Still not so clear how you can invoke the command "man unknown"?

>"[...] unknown checks to see if the command was invoked at top-level and outside of any script. If so, [...] unknown > checks to see if cmd is a unique abbreviation for an existing Tcl command. If so, it expands the command name
> and executes the command with the original arguments." Note that I left out several steps while shortening!
>
> And I prefer tab-completion (e.g. via tclreadline)

Interesting/wonderful feature which I still can't figure out how to
enable it. Can you share your settings for this functionality with me?
BTW, I've noticed some instructions from
<https://stackoverflow.com/questions/22967521/activating-auto-completion-in-tcl>
as shown below:

--------------------
You will find what you need at the TclReadline site. They suggest
putting the following in your ~/.tclshrc file:

if {$tcl_interactive} {
package require tclreadline
::tclreadline::Loop
}

I also added the following prompt to remind me I am using Tcl Readline:

proc ::tclreadline::prompt1 {} { return "%% " }
---------------------

heinrichmartin

unread,
Jan 18, 2021, 5:49:56 AM1/18/21
to
On Monday, January 18, 2021 at 10:23:57 AM UTC+1, HY wrote:
> On Monday, January 18, 2021 at 4:55:05 PM UTC+8, heinrichmartin wrote:
> > The documentation is in man unknown:
> Still not so clear how you can invoke the command "man unknown"?
> >"[...] unknown checks to see if the command was invoked at top-level and outside of any script. If so, [...] unknown > checks to see if cmd is a unique abbreviation for an existing Tcl command. If so, it expands the command name
> > and executes the command with the original arguments." Note that I left out several steps while shortening!

I referred to the man pages, but it is online if you prefer https://www.tcl-lang.org/man/tcl8.6/TclCmd/unknown.htm.

> > And I prefer tab-completion (e.g. via tclreadline)
> Interesting/wonderful feature which I still can't figure out how to
> enable it. Can you share your settings for this functionality with me?
> BTW, I've noticed some instructions from
> <https://stackoverflow.com/questions/22967521/activating-auto-completion-in-tcl>

You found it at SO. Other sources would be
* the man pages if installed from a Linux distro
* the components source and/or documentation, e.g. https://github.com/flightaware/tclreadline

To me question marks are indicators that someone is (still) looking for answers; I am not sure why or what you asked after finding the answer on your own. I am not asking for an answer here, but please consider what resources you (want to) allocate ;-)

Hongyi Zhao

unread,
Jan 18, 2021, 9:32:55 AM1/18/21
to
On Monday, January 18, 2021 at 6:49:56 PM UTC+8, heinrichmartin wrote:
> On Monday, January 18, 2021 at 10:23:57 AM UTC+1, HY wrote:
> > On Monday, January 18, 2021 at 4:55:05 PM UTC+8, heinrichmartin wrote:
> > > The documentation is in man unknown:
> > Still not so clear how you can invoke the command "man unknown"?
> > >"[...] unknown checks to see if the command was invoked at top-level and outside of any script. If so, [...] unknown > checks to see if cmd is a unique abbreviation for an existing Tcl command. If so, it expands the command name
> > > and executes the command with the original arguments." Note that I left out several steps while shortening!
> I referred to the man pages, but it is online if you prefer https://www.tcl-lang.org/man/tcl8.6/TclCmd/unknown.htm.

Thanks for your clarification.

> > > And I prefer tab-completion (e.g. via tclreadline)
> > Interesting/wonderful feature which I still can't figure out how to
> > enable it. Can you share your settings for this functionality with me?
> > BTW, I've noticed some instructions from
> > <https://stackoverflow.com/questions/22967521/activating-auto-completion-in-tcl>
> You found it at SO. Other sources would be
> * the man pages if installed from a Linux distro
> * the components source and/or documentation, e.g. https://github.com/flightaware/tclreadline
>
> To me question marks are indicators that someone is (still) looking for answers; I am not sure why or what you asked after finding the answer on your own.

I'm just curious if there are any more elaborate/orchestrated control settings.

> I am not asking for an answer here, but please consider what resources you (want to) allocate ;-)

I'll if I have ;-)
0 new messages