Temporary files are frequently used in shell scripts. In a typical shell script often some data is processed, and the results are written to a scratch file, the new data is processed in another way, and eventually the scratch file is removed.
So why write an article about this topic?
Often shell script programmers use temporary files in their scripts, and remove them at the end of the program. This simple and straight forward approach works well as long as a user does not interrupt the script using a signal (i.e. by pressing ^C or DEL). In this case the script doesn't have a chance to remove its temporary files before closing.
This article shows how to intercept interrupts from shell scripts.
This script passes its command line arguments on to the man command, and writes the result to a temporary file /tmp/viman. Before starting vi on the file, all control characters are removed ("col -b"), and duplicate or empty lines are removed ("uniq"). After vi terminates, the file is removed.
This simple script has two drawbacks.
Consider what happens if two people call this script, one after
the other. The first one has his manual page written to
/tmp/viman. Shortly after that the second one has his
manual page written to the same file, overwriting the contents of
the first manual page.
Now the first user gets the wrong manual page in the
The solution to this problem is clear: each user needs
to have a unique temporary file, but how to do it? We could try to
create the temporary file in the directory
Steve Bourne (the creator of the Bourne Shell) suggests in The UNIX system to use the unique process identifier (PID) of the shell script as part of the file name. Since the process id of the script is always available via the environment variable $$, we could rewrite the script as follows:
This small change solves the problem.
But one problem remains: what happens to the temporary file, if the script is terminated with a signal? In this case, the temporary file may is not removed, because the last line of the script is never reached!
You may think: "Who cares about files clogging up the /tmp directory? The directory gets cleaned up automatically anyway!" On the other hand you are reading this text to become a better shell programmer, and could be excited to come to know there is an easy way to "trap" signals from a shell script.
The general syntax for the
Signals may be specified using numbers (0 to 31),
"0" being a pseudo-signal meaning "program termination". The Korn
shell also understands names for the signal, i.e.
A simple example would be:
This means: execute the command "
Only one refinement has to be made before we can present The Canonical Way To Handle Temporary Files ©. Suppose we use the following line in our script:
If somebody sends the SIGTERM signal to our script (i.e. by entering "kill -15 scriptpid"), the following would happen:
A better (and the recommended) way to handle the signals is as follows:
The first trap ensures that the temporary file
The second trap causes our script to terminate after receiving one of the specified signals. Before the script terminates, the trap for "signal" 0 is executed, effectively removing the temporary file.
Our original script, now rewritten to handle signals and use unique temporary files looks as follows:
Handling signals requires a bit more overhead; perhaps overkill for simple scripts like this one but definitely worthwhile for complex scripts.
Copyright © 1998-2022 Heiner Steven (firstname.lastname@example.org)