Are `if` and `then` actually programs

The ; separates statements (loosely speaking). It is (almost) always possible to replace a ; by a newline.

To say that ; separates two programs, therefore if and then must be "programs" is a bit too simplistic as a statement may be made of reserved words, shell functions, built-in utilities and external utilities, and combinations of these using pipes and boolean operators etc. etc.

Both if and then are reserved words in the shell grammar, not "programs". Here they are used to build up what's technically called a compound command.

echo is likely a built-in utility in the shell (but doesn't need to be), and ls is probably an external utility (or "program" as you say).


Whilst that is a fair first approximation when one is starting out learning the very basics of using shells, at the level of "here is how one runs a program" and "here is how one runs multiple programs one after another on a single line", it is not actually true.

The harder to grasp for a beginner but more correct explanation is that the shell language is a computer language. It has a syntax. That syntax comprises various lexical elements including (amongst other things) newlines, operators, words, and reserved words.

if, then, else, and fi are all reserved words. They have particular meanings when parsing the input that one gives to a shell, according to its grammar. Similarly, ; is a separator operator.

Input in the shell language is thus, taken as a whole, a computer program that is interpreted by another program, an interpreter, the shell. Its individual grammatical parts are not programs. The shell language is a way of specifying (other) programs for the shell to run.

[ is not a special lexical element in the shell grammar such as an operator. It is an ordinary word, that names one such program named [. Many shells have a built-in version of this program, combined into the code of the shell program itself, but you can also find an external program by this name somewhere such as /bin/[ or /usr/bin/[, which programs other than shells can invoke. Equally, ] isn't a special shell lexical element either. It's an ordinary word, that becomes an argument for the [ program. The [ program requires that its final argument, when it is executed, be ], which it proceeds to then ignore.

Another similar program named in your question is echo. Again, most shells have a built-in version of this program. But again there is also an external version of the program, somewhere such as /bin/echo or/usr/bin/echo, for programs other than shells to invoke.

A third program named in your question is ls. Shells generally do not have built-in versions of this program, and it is an external program, to be found somewhere such as /bin/ls or /usr/bin/ls.

For the Bourne Again shell, you can read more about this in the Basic Shell Features of the GNU Bourne Again shell info documentation. Other shells have different grammars, naturally. The Single Unix Specification describes a syntax that all POSIX-conformant shells (in their POSIX-conformant modes) are supposed to adhere to.

Further reading

  • "Shell Grammar". Shell Command Language. Base Specifications Issue 7. The Open Group. IEEE 1003.1-2008. ISBN 1937218812.
  • test. Utilities. Base Specifications Issue 7. The Open Group. IEEE 1003.1-2008. ISBN 1937218812.
  • "Shell Grammar". The Z Shell Manual. version 5.3.1. 2017.

It is actually not far-fetched to think of if, then and else as external programs. In fact, the Thompson shell in the original 1st edition Unix implemented if and goto as external programs. This is possible because the subprocess shares file descriptors with the shell process, so a (forward) goto just had to read input until it finds the target label and then exits. See Thompson shell.