Many people who think they need Expect do not need Expect

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.