Notes on The Unix Programming Environment

This document provides notes and comments on, as well as my solutions to exercises found in, The Unix Programming Environment by Brian W. Kernighan and Rob Pike. I've decided to restrict myself to notes on exercises and examples. As the Preface states, "This book should be read at a terminal, so that you can experiment, verify or contradict what we say, explore the limits and the variations." Exploring any operating environment exposes many details, which I leave to other notes and reflections related to particular systems, or books I've read (or in some cases written for Linux administration and programming instruction, of which this book was always a key reference).

Most Unix systems of today fall into a few categories. There's the classic BSD systems like OpenBSD, NetBSD, FreeBSD, and DragonFly BSD. There's also the POSIX compliant, trademarked UNIX® systems, which include a couple of Linux systems, HP-UX, Solaris, AIX, and macOS. There's also many different Linux systems, including commercial systems such as Red Hat Enterprise Linux, Ubuntu, and SUSE, and other clones such as Minix. This document looks mostly at working through the exercises on Slackware64 as installed on a Dell Precision T5400.

A reference to the Unix Programmer's Manual refers to two basic books: the man pages and the articles. For the purpose of this book, the Seventh Edition UNIX system from Bell Labs is what it means here. The Tenth Edition was the final research release. I understand that the Eighth Edition sources have been posted to the Unix Heritage Society website. System III and System V from the Unix Systems Laboratories was the commercial branch of Unix. For Slackware64, this basically means the man pages and explanatory white papers provided with the system, and perhaps the POSIX and LSB (ISO/IEC 23360-1:2006) standards.

Chapter 1

RETURN in the book refers to the key that generates the carriage return control character. PC keyboards usually have Enter now, but it’s the same key. Also, the Backspace key means send the backspace character then send the delete character. As the book noted, sometimes the Delete key may do other things than delete a character.

Mistakes in typing

Towards the end of section 1.1, Mistakes in typing describes shell behavior that is likely confusing to modern users. Being able to backspace and delete something previously typed was not available. Bill Joy distributed a tape called the Berkeley System Distribution (BSD) that included a visual editor (ex and vi) and the C Shell (CSH), which introduced the idea of being able to edit the command line and correct mistakes. The GNU Project's Bash, which is at the core of most Unix systems today (though older ones still use the Korn Shell replacement to Bourne's), defaults to Emacs mode. This provides not only command editing and correction, but command completion options, and history paging.

To get the old fashioned behavior in Bash, instead of using @ character for line kill, use Ctrl-u. To erase the previous character, type Ctrl-\? (hold down both the Control/Ctrl key and and the backslash key, then type the key with the question mark (the Shift key is not necessary here). However, to accomplish Exercise 1-1, these must be remapped to the @ and # characters, respectively. Typing stty -a using the GNU Coreutils stty command will show the current settings. An initial start is as follows:

$ stty erase \#Enter
stty kill @Enter

Unfortunately, this does not honor the \ character as an escape, so the example's \@ will still delete the line. The following is what the exercise was expected to look like:

$ date@

Notice that the trailing $ is not present, so the book does not expect you to type the Enter key, but instead expected the \@ part of your typing to not print the \ part. As the book indicated, typically this will still put you on a new line with a prompt. If you got command not found, then you pressed Enter when typing date\@, which makes sense: there's no date\@ command, only date, and the @ character is not being interpretted as a line kill, nor is the \ escaping it.

For now, that's as far as I got. With some more persistence, I'm sure I could identify why the \ character is not escaping the control characters defined by the stty command, and also identify how to explain how to set everything back the way it was easily. For now, you may have to log out, then back in again, or use the stty command to configured the old behavior. So with Bash on GNU/Linux and macOS, use Backspace instead of # (as the book suggests you test), and Ctrl-u instead of @.

Exercise 1-2 has four commands. The first types the date command with the expected output. The second has a # that has nothing to delete before running the date command. The third escapes the # which becomes a comment. The fourth escapes the escape to a literal \, which then escapes the # to a comment (instead of a backspace+delete), and thus returns from Bash a command not found.

Stopping a program

This section may not make sense until it is realized that slow baud rate serial connections using dumb terminals and dial-up modems is assumed here. Unless dealing with network or internet latency, the X/ON and X/OFF behavior of the Break key, or Ctrl-q and Ctrl-s won't make sense.

Writing to others

Typically, the Delete key does not break out of a write session, only Ctrl-d. Only my Microsoft Natural Keyboard appears to still have a Pause or break key, but it does not break out of a write session either.

The manual

Unix and Plan 9 printed the entire manual to the screen (all available sections, instead of only the first). Part of this is because of the default behavior of the man and man-db packages, as originated from BSD, of using the more pager (and on GNU/Linux, the less pager) by default. Some systems even have plain text (cat) directories (e.g. /usr/man/cat1/ instead of /usr/man/man1/) where the man page can be printed with cat or searched directly with the grep command. Scrolling the screen on Linux can be done by holding down the Shift key, and pressing PgUp or PgDown. Within a graphical windowing environment, the screen can be scrolled with a mouse, and some graphical terminal emulators can be configured with infinite scroll back (otherwise typically restricted).

To quit a manual type q. Use the space bar or Enter to move forward in a manual, or b or Ctrl-b to move back. Search with the / character.

Computer aided instruction

The learn command is typically not found on Linux systems. Professor Kernighan (the author) has a copy from research Unix at his Princeton mirror.

Home directories

Research Unix home directories were in /usr/ (for user). Most Linux systems use /home/, and even have a /root/ (restricted) home directory. This can be confusing keeping the root (/) and root home (/root/) directory distinct in your mind. The administrative user is ID number 0, called root (instead of something like adm) because it is the user without a home directory that defaults to the root directory, (at least in research Unix).

Most Unix systems have removed the . from the path, meaning commands in the current working directory won't execute by default. This is to avoid trojan attacks.

dot files

On occasion, files like .profile are mentioned as being in your home directory. A file that starts with a dot is treated as a hidden file by some programs, and depending on configuration the shell. For instance, ls * in the book is shown to print the dot files, but not with Bash on GNU/Linux systems or macOS. This makes things trickier to handle those hidden files. The Unix researchers later decided that it is probably best to not treat the files as hidden after all, but so many programs store their configurations in these dot files, instead of say $HOME/etc/, that using your home directory for files in general is likely not a good idea if those files aren't treated as hidden.

The explanation in a foot note regarding .profile seem to assume that it is read with every shell, and thus every command, invocation. I don't know when (if?) this changed, but shells like the Korn shell, Bash, CSH, and ZSH all have a run commands file (e.g. .bashrc) that does this, and the $HOME/.profile and /etc/profile are only read at login (unless explicitly invoked, e.g. su -).

Mistakes in the chapter 1 text?

The PS1 example in my edition of UPE was missing the closing apostrophe-quote. I also noticed in the -t explanation at the top of page 14 that it describes it as "recent use", but the ls defaults to printing the modification time not the access time.

©2019 David Egan Evans.