On this bash scripting example page the author presents this script:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

Why would you cat /dev/null onto anything? I can’t understand what’s intended here (is it like using while TRUE; sleep 1; elihw for {some busy program}?). Yet the author calls it “Nothing unusual.”

up vote 41 down vote accepted

You typically cat /dev/null > [something] when you want to wipe file contents while ensuring there is absolutely zero risk of interruption to the actual file state. The contents of the file will clearly be wiped by the cat /dev/null yet the file itself—as it exists and is known to the file system it resides on—will still be there with the same inode number, ownership and permissions.

In the case of a log file, it could be that the log file itself is marked “in use” by another process. So doing—for example—an rm /var/log/messages && touch /var/log/messages would be disruptive to other processes and might cause running processes to choke. Meaning a process that somehow is locked to a specific inode number connected to the file /var/log/messages could suddenly panic and say, “Hey! What happened to /var/log/messages!” even if the file is still there. Not to mention potential issues with ownership and permissions being incorrectly recreated.

Because of this uncertainty in usage/state of a file the use of cat /dev/null > [something] is preferred by system admins who want to clear out a log but do not want to potentially interfere with the operation of already existing processes.

Also, in the context of the page you link to the author states the following:

There is nothing unusual here, only a set of commands that could just as easily have been invoked one by one from the command-line on the console or in a terminal window. The advantages of placing the commands in a script go far beyond not having to retype them time and again.

So the “nothing unusual” the author mentions is with regards to the whole concept of what that specific bash script is: It’s just a set of simple commands that can just as easily be run from the command line but are placed in a text file to avoid having to retype them over and over again.

  • 10
    @jlliagre The only thing being "kept alive" is the context of the question which is focused on why the original author would do that. If you are impassioned as to dispelling the "myth" please post an answer that provides context for the original author's coding method as well as perspective on why you believe it can be replaced by other methods. – JakeGould Dec 6 '14 at 20:59
  • 7
    @jlliagre Cyrus's answer does not address the core question of why the original author would have used that method nor the reasoning behind it. The tutorial mentioned is quite old and reasonably accepted. It is not incorrect nor does it perpetuate a supposed "urban legend." Rather it is the way one person codes versus the way another person codes. As simple as that. It is a style issue that has no negative impact on reliability or performance. – JakeGould Dec 6 '14 at 21:12
  • 3
    truncate -s 0 would do the same thing and be less idiomatic. However, shell programmers are a conservative bunch and one might encounter systems old enough or wacky enough to be lacking that command. – Schwern Dec 9 '14 at 5:32
  • 5
    @skift cat /dev/null > /foo/bar truncates the file; echo "" > /foo/bar truncates it and then writes a single newline character. – David Dec 10 '14 at 2:59
  • 2
    Another advantage of this method over rm & touch is that ownership and permissions are maintained. – jjmontes Dec 10 '14 at 13:30

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:

  • Explicitly printing an empty string to the file:

    printf "" > file
    
  • Using the true command which is strictly equivalent to the no-op one : albeit more readable:

    true > file
    
  • 1
    @JonathanLeffler I believe It is part of all current csh implementations although it is not necessarily documented. From the Solaris csh manual page : Null command. This command is interpreted, but performs no action.. I found no mention of the same in either the tcsh manual page or the original BSD csh ones but this syntax might have always worked. – jlliagre Dec 7 '14 at 9:50
  • 6
    One reason for writing cat /dev/null is to make your intentions explicit. – Davidmh Dec 8 '14 at 18:22
  • 1
    @Davidmh That would be sensible but your statement doesn't resist fact checkings. I have observed this shell idiom for probably a couple of decades. When I had the opportunity to ask to the author the reasoning behind it, I always got unsound theories about using /dev/null being an efficient way to inject zero bytes, anyway a more reliable one than using : or nothing. In this very page, Cyrus answer which was terse but straight to the point had zero votes while JakeGould's one who was challenging the fact cat /dev/null was a no-op (see our comments) already had at least four votes. – jlliagre Dec 8 '14 at 21:42
  • 2
    @jlliagre my knowledge of the shell is pretty basic, so I am perhaps not the best population target; but a bare > or : is not clear. I agree it is a shame that myths have been propagated due to its use. – Davidmh Dec 9 '14 at 9:12
  • 3
    @Davidmh If you really want something explicit before the redirection, I would recommend printf "" > file which is both portable (POSIX) and lightweight as often implemented as a shell builtin. – jlliagre Dec 9 '14 at 9:36

It is a cumbersome way to bring the file to zero size.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
  • This syntax won't work in every shell. – reinierpost Dec 10 '14 at 11:04
  • 2
    Correct. The question is only tagged with "bash". – Cyrus Dec 10 '14 at 11:06
  • @reinierpost It will work in all Bourne-style shells, won't it? Let's not worry about csh. – Barmar Dec 12 '14 at 19:20
  • : > messages also works. : or true are the more obvious choices for commands that print nothing and return true. – Peter Cordes Jan 28 '15 at 1:56

To truncate an open file. This is equivalent, and more comprehensible:

echo -n > /var/log/messages

(Added -n to avoid the newline)

  • 3
    This is indeed more comprehensible but unfortunately not a equivalent. It will even break functionalities like in the wtmp case. See my updated answer. – jlliagre Dec 7 '14 at 21:00
  • echo -n avoids newline. – bbaassssiiee Dec 7 '14 at 21:08
  • 5
    It will indeed if you are sure to use bash, -n is otherwise not guaranteed to work in all Bourne shells. – jlliagre Dec 7 '14 at 21:10

protected by JakeGould Oct 6 '15 at 4:53

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.