Skip to content
Lesson 5 of 16

Step 1 of 5 · Reading · ~3 min

Read

Built-ins & Variables

Built-in Commands: cd, pwd, exit

After this lesson your shell changes directory for real: cd updates the shell's own working directory, cd - goes back and says where it went, pwd and $PWD agree, a failed cd leaves everything as it was, and exit stops the shell with a status. The directories are virtual here, so you can test every case without touching a disk.

Why cd cannot be a program

Every other command you type is run by forking a child and calling exec in it. Try that with cd:

shell (cwd /home/user)
  |-- fork --> child: chdir("/tmp"), then exits
shell (cwd still /home/user)

A working directory belongs to a process. The child changes its own and dies; the shell's is untouched. The same holds for exit, for variable assignment and for exec. They must run inside the shell process, and that is the definition of a built-in. The shell checks its built-in table before it forks.

State a shell keeps

  • PWD, the current directory, as an absolute path.
  • OLDPWD, the directory before the last successful cd. It starts unset.
  • $?, the exit status of the last command: 0 for success, non-zero for failure, 127 for a command not found.

What cd does

  1. No argument means HOME. A leading ~ means HOME, so ~/docs is HOME/docs.
  2. The argument - means OLDPWD and, as the one case where cd prints, writes the new directory. If OLDPWD is unset, the error is cd: OLDPWD not set.
  3. A relative path is joined to PWD. Then the path is normalized textually: repeated slashes collapse, . disappears, and .. removes the previous component (at the root it stays at the root). This is the logical cd -L behaviour that shells default to.
  4. If the result is not a directory, print cd: <argument as typed>: No such file or directory, set status 1 and change nothing, including OLDPWD.
  5. On success set OLDPWD to the old PWD, PWD to the new path, and status 0.

More than one argument is cd: too many arguments, status 1.

exit

exit stops the shell. With a number it uses that number modulo 256, so exit 256 is 0 and exit -1 is 255; with no argument it uses the status of the last command. A non-number prints exit: <arg>: numeric argument required and the status is 2. Too many arguments prints exit: too many arguments and, unusually, does not exit.

A worked trace

Start in the home directory. cd /tmp sets OLDPWD to the home directory. cd - prints the home directory and swaps the two. Another cd - prints /tmp. If a cd /missing came between them, nothing would change, so both swaps would still work.

Common mistakes

  • Printing the directory after every cd. Only cd - prints.
  • Updating OLDPWD before you know the cd will succeed.
  • Letting .. climb above the root, or leaving // or /./ in the stored path.
  • Reporting the normalized path in the error message instead of the argument as typed.

Your exercise

The starter keeps the directory table, the path normalizer and the line loop, and handles the setup lines that create directories. You write the command dispatcher. The most likely mistake is changing OLDPWD on a failed cd.

Up nextEnvironment Variables & ExpansionBuilt-ins & Variables

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…