Programs That Ignore Eof

There is an exception to the scenario that I just described. Some interactive programs are rather cavalier when they encounter an eof and do not handle it correctly. However, if you are prepared for this situation, you can work around it easily enough. There are two kinds of common misbehavior:

  • Some programs ignore eof.

  • Some programs ignore data just before eof.

I will discuss the two cases separately.

Some programs ignore eof. Even if you close the connection (by calling close, exiting the script, or pressing ^C), they ignore the eof and continue waiting for more characters to arrive. This is characteristic of the ubiquitous telnet implementation and many other programs that run in raw mode. Raw mode means that no special interpretations are applied to input characters. For instance, ^C no longer serves as an interrupt, and ^D no longer acts as an eof. Since users cannot send an eof, these programs have no reason to expect it and thus do not look for it. The problem is, an eof is exactly what they get when the connection is closed.

Avoid explicitly closing programs like these before they are ready. Instead, force them to close the connection in the way they would when using them manually. For instance, telnet will close the connection on its own once you log out of the remote host. If you do not gracefully log out, thereby letting telnet shut down the connection, you will be left with a telnet process on your system talking to no one. Such a process must then be killed by hand using the UNIX kill command. (It is possible to do this from Expect, but I will not go into it until Chapter 13 (p. 292).)

Some programs detect eof but ignore any other data that comes along with it. An example is the following Expect script which runs ftp. Three files are requested but after the script has finished, only two of the files are found.

spawn ftp . . .
# assume username and password are accepted here
expect "ftp> " {send "get file1\r"}
expect "ftp> " {send "get file2\r"}
expect "ftp> " {send "get file3\r"}

After sending "get file3\r“, Expect immediately closes the connection to ftp and exits. Then ftp reads the command but also finds the eof as well. Unlike telnet in the previous example, ftp checks for the eof but it mistakenly assumes that the eof also means there is no data to process. It simply does not check and therefore the "get file3\r" is never done.

In this example, the solution is to add a final expect command to wait for another prompt. An even simpler example is the following script which starts the vi editor and sends a command. The command inserts "foo" into a file which is then saved. The "q" tells vi to quit.

spawn vi file
send "ifoo\033:wq\r"

Because of the final quit command, there is no prompt for which to wait. Instead, it suffices to wait for an eof from vi itself. And since the eof has no action, the eof keyword can be omitted as well. Here is the corrected script:

spawn vi file
send "ifoo\033:wq\r"
expect

Spawned processes that exit on the hangup signal behave similarly to programs that ignore data just before an eof. The solution is the same. Wait for the spawned process itself to close the connection first.

Get Exploring Expect now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.