Expect is a wonderful tool. Many people use it without realising it's a Tcl extension. Many people use it when they don't actually need it. Many people who don't use it forget the convenient facilities it provides.
Primarily, Expect provides three things:
* [pty] support. This is Expect's big draw, allowing it to drive programs which were never intended to be automated.
* [signal]s. A convenient way to add signal support to your scripts is `package require Expect; trap {puts {no interruptions!}} SIGINT`
* the [expect] control structure and all its wonderful friends ([expect_background], [interact], ...). Not to be underestimated.
Traditionally,
pty support is the big card that ties people to Expect. An incredibly common use-case is driving SSH connections to administer remote machines. Some anti-patterns in this scenario:
* using [expect] to send passwords: use key based authentication!
* getting past the "unknown host key" message: use options `-q -o 'StrictHostKeyChecking no'`
* if you're just running a single, non-interactive command, put it on the ssh command line and be done with it.
Crucially, OpenSSH doesn't actually require a local PTY! Just use the
-t option, twice:
set user $::env(USER)
set host localhost
set ssh [open "|ssh -tt -q -o {StrictHostKeyChecking no} $user@$host /bin/sh" r+] ;# hint: not using a login shell can make output easier to consume
fconfigure $ssh -buffering line -blocking 1 -translation lf
while {[read $ssh 1] ne "$"} {} ;# wait for a prompt
puts $ssh "uptime; exit"
gets $ssh ;# consume the line we just sent
set uptime [read $ssh] ;# read until EOF
close $ssh
puts "Uptime on $host: $uptime"
Automating complex interactivity without the
expect command, you will quickly come to miss it. But if all you need to do is snatch some output, tail some logs or run a single command the above pattern can be useful. It allows you to ship your solution without a binary extension, and makes it more obvious how to use modern Tcl features like
coroutines,
[Non-blocking IO
] and
[Channel Transformers
].
The
expect DSL is a bit awkward by modern Tcl standards, but it's excellent for abstracting protocol interaction. Today, it should probably be rewritten in pure Tcl, using up-to-date idioms,
TclOO and
coroutines ... but there is a
lot of non-obvious wisdom embedded in the design of Expect which is non-trivial to extract.