Although Unix shells make no distinction between commands entered from the keyboard and those input from a script, there are certain shell features that are meant for scripting and not convenient or useful to use interactively. Many of these features will be familiar to anyone who has done computer programming. They include constructs such as comments, conditionals (e.g. if commands) and loops. The following sections provide a very brief introduction to shell constructs that are used in scripting, but generally not used on the command line.
A string constant in a shell script is anything enclosed in single quotes ('this is a string') or double quotes ("this is also a string").
Unlike most programming languages, text in a shell scripts that is not enclosed in quotes and does not begin with a '$' or other special character is also interpreted as a string constant. Hence, all of the following are the same:
shell-prompt: ls /etc shell-prompt: ls "/etc" shell-prompt: ls '/etc'
Most programming languages would interpret the '/' as a division
etc as a variable name. As you
can see, Unix shell languages differ from general purpose languages
If a string contains white space (spaces or tabs), then it will be seen as multiple separate strings, unless we explicitly state otherwise by enclosing the string in quotes or escaping every white space character. The last example below will not work properly, since 'Program' and 'Files' are seen as separate arguments:
shell-prompt: cd 'Program Files' # One directory name shell-prompt: cd "Program Files" # One directory name shell-prompt: cd Program\ Files # One directory name shell-prompt: cd Program Files # Two directory names
Special sequences such as '\n', which represents the newline character, must be enclosed in quotes or escaped. Otherwise, the '\' is seen as escaping the 'n', which has no effect. Remember that '\' tells the shell to not to interpret the next character as special. This is useful behind a special character such as '*' or '[', but 'n' has no special meaning in the first place, so a '\' before it will not alter its interpretation.
#!/bin/sh -e printf Hello\n printf "Hello\n" printf Hello\\n HellonHello Hello
Output commands are only occasionally useful at the interactive command line. We may sometimes use them to take a quick look at a variable such as $PATH. Output commands are far more useful in scripts, and are used in the same ways as output statements in any programming language.
The echo command is commonly used to output text to the terminal:
shell-prompt: echo 'Hello!' Hello! shell-prompt: echo $PATH /usr/local/bin:/home/bacon/scripts:/home/bacon/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin
However, echo should be avoided, since it is not portable across different shells and even the same shell on different Unix systems. There are many different implementations of echo commands, some internal to the shell and some external programs. Different implementations of echo use different command-line flags and special characters to control output formatting. In addition, the output formatting capabilities of echo commands are extremely limited.
The printf command supersedes
echo. It has a rich set of capabilities
similar to the
printf() function in the standard
C library and in Java. The printf command
is specified in the POSIX.2 standard, so its behavior is largely
the same on all Unix systems. Printf is an
external command, so it is independent of which shell you are
using. Unlike echo, it does not add a newline
character by default.
shell-prompt: printf 'Hello!\n' Hello!
The general syntax of a printf command is as follows:
printf format-string [arguments]
The format-string contains literal text and a format specifier to match each of the arguments that follows. Each format specifier begins with a '%' and is followed by symbols indicating the format in which to print the argument.
The format string can be the sole argument to printf, as long as it does not contain any specifiers. Otherwise, there must be exactly one argument following the format string to match each specifier.
Table 4.3. Printf Format Specifiers
|%20s||String right-justified in a 20-character space|
|%-20s||String left-justified in a 20-character space|
The printf command also recognizes most of the same special character sequences as the C printf() function:
Table 4.4. Special Character Sequences
|\n||Newline (move down to next line)|
|\r||Carriage Return (go to beginning of current line)|
|\t||Tab (go to next tab stop)|
#!/bin/sh -e printf '%s.\n' 'This is default format' printf '%50s.\n' 'This is right-justified' printf '%-50s.\n' 'This is left-justified'
This is default format. This is right-justified. This is left-justified .
There are many other format specifiers and special character sequences. For complete information, run man printf.
Any program that prints error messages should send them to the
standard error, not the standard output. The
printf command always outputs to the standard
output, but we can work around it using redirection to
printf 'Error: Input must be a number.\n' >> /dev/stderr
Write a shell script containing the printf command above and run it. Write the same script using two different shells, such as Bourne shell and C shell. What is the difference between the two scripts?
How does the Unix shell interpret the character sequence
firstname? How would it be interpreted by
most general purpose programming languages?
Show three ways to make the shell see the character sequence
Alfred E. Neumann as a single string rather than
three strings. Note that there are two spaces after the period.
What is the output of the following statement? How do we make it interpret the \n as a newline?
#!/bin/sh -e printf \$15*3=\$45\n
What are some of the problems with the echo command? What is the solution?
Show a printf statement that prints the number 32,767, right-justified in a field of 10 columns.
Show a printf statement that prints the error message "Error: Invalid data found in column 2 of input." to the standard error.