Main index

Introducing UNIX and Linux


Introduction to shells

Overview
Why do we need a shell?
Shell syntax
      Types of shell command
      Simple commands
      Pipelines
      Grouping commands
      Exit status
      List commands
Arithmetic
      Operators and functions
Making decisions
      The 'test' statement
            Operators used by 'test'
      The 'if' statement
Loops
      'For' loops
      'While' and 'until' loops
Searching for files
      Arguments to 'find'
Formatted output
      Arguments to 'printf'
Passing information to scripts
      Scripts with arguments
      Parameter expansion
Summary
Exercises

Grouping commands

Occasionally it will be necessary to group commands together so that they appear to the shell as a single command. For instance, suppose you wish to print a text file (myfile, say) on the printer, and you wish to append lines both at the start and at the end of the file. If this is to be performed in a script, you cannot use vi, since vi does not use standard input and standard output in a simple manner. What you also cannot do is to send the standard output of the echo and cat commands to lp (or lpr) separately - you would then get the header and footer messages printed on separate pages. There are several solutions that you will already be able to use.

The first involves creating a temporary file to store the output, and then using cat on that file:

echo "This is the start" > temp
cat myfile >> temp
echo "This is the end" >> temp
cat temp | lp

This is inelegant and to be discouraged - proliferation of temporary files causes confusion and wastes storage space. The second involves creating a script to perform the task, so:

cat <<END >temp
echo "This is the start"
cat myfile
echo "This is the end"
END

sh temp | lp

This method also uses a temporary file, but we can substitute the occurrence of temp for standard output, and pipe it to sh:

cat <<END | sh - | lp
echo "This is the start"
cat myfile
echo "This is the end"
END

By using the latter method we have overcome the need for a temporary file by taking the commands for sh from standard input explicitly by using the hyphen. What we have done is to anonymise the temporary file. However, we can improve on the here-document method by means of a technique called command grouping.

By enclosing a list of commands in parentheses, a new invocation of the shell is formed to execute that list of commands, just as if you had placed those commands in a file and run that file as a separate shell script. The solution to the above problem then becomes:

( echo "This is the start"
> cat myfile
> echo "This is the end" ) | lp

If a sequence of commands (which can be separated either by newlines or by semicolons) is enclosed in parentheses, then they will be executed in sequence, and their output streams will be concatenated together to form a single stream, which can itself then be redirected.

Worked example

Without creating any temporary files, and using a single shell command, instruct your shell to display the names of files in the current directory, preceded by an explanatory message, and paged (in case you have a large number of them).
Solution: Use ls to list the files, echo to produce a message, and more as the pager. Then use command grouping to join the outputs of ls and echo together:

(echo "Your files are:"; ls) | more


Copyright © 2002 Mike Joy, Stephen Jarvis and Michael Luck