15

I've read that semicolon is used to separate programs:

$ echo 3; ls -la

Does it mean that if, then and else are separate programs here?

$ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fi

This question is not about semicolons.

5 Answers5

27

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).

Kusalananda
  • 333,661
7

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.
JdeBP
  • 68,745
5

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.

Johan Myréen
  • 13,168
2

The then and else are not programs. The other parts are. Notice there's no ;' directly after them, but after the command they precede.

The [ ... ] is a command, and needs the ; if followed by the beginning of another command.

AFAIK, all of control structures in Bash, and probably most *nix shells, are the same. They are instructions to the interpreter. The test or condition, on the other hand, uses a program/process that is "executed" and are commands. Since then is part of the line that leads to the echo command it has to be separated by a newline from the previous command [ ... ]. It doesn't need to be separated from the command it controls, the echo yes.

Legally, although ugly and hard to read, you could also do this.

if [ $VARIABLE == abcdef ]
then echo yes
else echo no
fi

Notice that there's no need for ; between the controls at all here, even though they are not on their own line.

Interestingly enough, the whole control structure (if ... fi) is a shell command, and the entirety has to end with a newline or a ;. The last line can't be fi echo done but must be fi; echo done. The same as an assignment VARIABLE='abcdef' is a command.

Even though the whole control structures are commands, they still are not programs.

Chindraba
  • 1,478
1

if, elif, then, and fi are all reserved keywords used to implement one of the constructs referred to as a compound command in shell, which means there cannot be a command (or rather, another command) by any of those names in shell. The purpose of the ; in general is not to separate commands, but to terminate a command list. For example, the following is a valid if statement:

if echo foo; echo bar; echo baz; then echo done; echo really done; fi

The condition of the if statement is the command list echo foo; echo bar; echo baz. The parser knows that the condition is over because then, which immediately follows a semi-colon, cannot be a command because it is a reserved keyword. Thus, it knows that what follows then is the start of the body. Likewise, fi is a reserved keyword and thus cannot be a third command in the body of the if statement, but marks the end of the compound command.

chepner
  • 7,501
  • thanks, if this is used if program1 foo; program2 bar; program3 baz;, which program status should be 0, so that shell proceeds to then? The last one? – Max Koretskyi Jan 22 '17 at 07:44
  • Just program3 baz. The exit status of a list of commands is the exit status of the last command in that list. The other two can fail without affecting the condition. – chepner Jan 22 '17 at 13:54