Most UNIX/Linux folks write shell scripts, often in an ad hoc manner, and there's an easy mistake that can be very painful: attempting to copy/move to target directories that do not exist.
Let's look at a contrived example, where we want to move *.old to a backup directory only if there is a corresponding *.new:
for f in CL*.new
do
oldname=`basename $f .new`.old # create the .old name from .new
if [ -f $oldname ] # does the file exist?
then
mv $oldname /home/backups
fi
done
The loop control looks fine, and when I ran this last week on another machine it worked great - so what's the problem here?
The problem is that if the /home/backups directory is missing, it will move each source file to the single file /home/backups, effectively overwriting all but the last file. This destroys data. Ouch.
Ok, so let's add some error checking to be safe, creating the directory if it's not there:
[ -d /home/backups ] || mkdir /home/backup
for f in CL*.new
do
oldname=`basename $f .new`.old
if [ -f $oldname ]
then
mv $oldname /home/backups
fi
done
Here, we've mistyped the directory name in the mkdir line, and the program destroys data the same way.
There are other ways to fix this, and at some point we have to take ownership of our own mistakes, but a really simple technique can mitigate much of this damage: always name directories with a trailing slash-dot:
for f in CL*.new
do
oldname=`basename $f .new`.old
if [ -f $oldname ]
then
mv $oldname /home/backups/. # added here
fi
done
The reference to slash-dot — no, not the geek website — insures that it's treated as a directory, and if it's not present (or if it's there but just a regular file), the command will fail outright:
$ ./myprog.sh mv: cannot move `CL1.old' to `/home/backups/.': No such file or directory mv: cannot move `CL3.old' to `/home/backups/.': No such file or directory
It may not be a graceful failure, but this little bit of defensive programming has saved my bacon a few times lately.




