Why would you cat /dev/null onto anything?
You'll do that to truncate a file contents while keeping the inode intact. All programs that have that file open for reading or writing wouldn't be affected outside the fact the file size would be reset to zero.
A bogus alternative often found is removing the file then creating it again:
rm file
touch file
or the similar:
mv file file.old
gzip file.old
touch file
The issue is these methods do not not prevent the old file from being kept written by whatever processes having the deleted file open at deletion time. The reason why is under Unix file systems, when you delete a file, you only unlink its name (path) from its content (inode). The inode is kept alive as long as there are processes having it open for reading or writing.
This leads to several negative effects: the logs written after the file deletion are lost as there is no straightforward/portable way to open a deleted file. As long as a process is writing to the deleted file, its content is still using space on the file system. That means that if you remove/create the file because it was filling your disk, the disk stays filled. One way to fix this latter issue is to restart the logger processes but you might not want to do that for critical services and intermediary logs would be definitively lost. There are also side effects due to the fact the file you create might not have the same permissions, owner and group than the original one. This for example could prevent a log analyzer to read the newly created file, or worse, prevent the logging process to write its own logs.
The first method, cat /dev/null > file
achieve the goal properly however, despite a tenacious urban legend, its cat /dev/null
part does absolutely nothing useful. It opens a pseudo file which is empty by design, it fails to read anything from it and finally just exits. Using this command is then a waste of keystrokes, bytes, system calls, and CPU cycles and it can be replaced without any functional change by the undoubtedly faster no-op command :
or even, with most shells, by no command at all.
Let me try a metaphor to explain how useless cat /dev/null
is. Let's say your goal is to empty a glass.
You first remove any liquid from it. That is sufficient and is precisely what (> file
) does given the fact redirections are always processed first.
Then, you pick an empty bottle (/dev/null
) and pour it in the empty glass (cat
). This is the pointless step ...
If you read your linked document to the end, you might notice the comments in this line from the enhanced version of the script:
cat /dev/null > wtmp # ': > wtmp' and '> wtmp' have the same effect.
They have indeed; too bad cat /dev/null
was kept in the code.
That means that the following code will work with all common shells (both csh
and sh
families):
cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."
and this will work with all shells using the Bourne syntax, like ash
, bash
, ksh
, zsh
and the likes:
cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Note however that with ancient, pre-POSIX Bourne shells, any of these commands, including cat /dev/null
won't truncate a file if it is written afterwards by a still running shell script appending to it. Instead of a zero byte file, that would be a sparse file with its size unchanged. The same would happen if the file is written by a process seeking to the position it thinks is the current one before writing.
Beware also that some alternative solutions often suggested to truncate a file do have flaws.
Both of the following ones just do not do the job. The resulting file is not empty but contains an empty line. This would break log files like wtmp
that store fixed width records.
echo > file
echo "" > file
The next one based on a BSD sh
option is not portable, POSIX doesn't specify any allowed options for echo so you might end up with a file containing a line with "-n
":
echo -n > file
That one not portable either by using a System V sh
escape sequence. Some shells will create a file containing a line with "\c
":
echo "\c" > file
That one uses a command designed to do the job. The issue is using truncate
is not portable because this command, not being specified by POSIX, might be missing from a Unix/Linux system.
truncate -s 0
Finally, here are a couple of alternatives that are portable and will properly do the job: