Why would you `cat /dev/null > /var/log/messages`?

77

18

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.”

isomorphismes

Posted 2014-12-06T19:40:17.323

Reputation: 1 534

Answers

40

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.

JakeGould

Posted 2014-12-06T19:40:17.323

Reputation: 38 217

-1 for keeping alive the urban legend cat /dev/null > has some magic power. cat /dev/null does nothing useful so can be replaced by the no-op command : or just no command at all as the redirection alone works under most shells. – jlliagre – 2014-12-06T20:54:20.950

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 – 2014-12-06T20:59:00.637

Cyrus already posted a correct, albeit terse, answer. – jlliagre – 2014-12-06T21:05:41.850

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 – 2014-12-06T21:12:00.357

1Granted, posting my own reply as you suggested then. – jlliagre – 2014-12-06T21:24:31.763

1ok, but implicit in "Nothing unusual" is that typing this command is not unusual either. (Which makes sense why anyone would do this after reading your answer. Thanks.) – isomorphismes – 2014-12-09T04:59:41.100

@isomorphismes Fair enough, but you can’t always control semantics of context for documentation written essentially years ago. – JakeGould – 2014-12-09T05:03:18.840

3truncate -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 – 2014-12-09T05:32:26.580

1@Schwern Shell programmers defer to being conservative because you are really often using scripts/tools when jumping from system to system and you don’t have the time to finesse code from install to install. Shell programming is just weird but necessary and useful. – JakeGould – 2014-12-09T05:34:07.833

1Curious, how is this different from echo "" > /foo/bar
which seems to me to do the same thing
– skift – 2014-12-09T22:32:24.600

5@skift cat /dev/null > /foo/bar truncates the file; echo "" > /foo/bar truncates it and then writes a single newline character. – David – 2014-12-10T02:59:58.517

2Another advantage of this method over rm & touch is that ownership and permissions are maintained. – jjmontes – 2014-12-10T13:30:17.753

1@jjmontes That point is implied by the inode number being the same, but hey it’s not clear if you don’t know what an inode is so I have edited this to reflect that aspect more clearly. Thank you! – JakeGould – 2014-12-10T16:32:03.700

@JakeGould Oh definitely. Hence why I'm thankful to SU answerers. – isomorphismes – 2014-12-10T23:13:45.830

@skift See the responses to the answer below that uses echo -n >file – isomorphismes – 2014-12-10T23:15:53.130

120

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
    

jlliagre

Posted 2014-12-06T19:40:17.323

Reputation: 12 469

Is the colon command a part of csh? – Jonathan Leffler – 2014-12-07T08:00:10.953

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 – 2014-12-07T09:50:49.123

6One reason for writing cat /dev/null is to make your intentions explicit. – Davidmh – 2014-12-08T18:22:08.337

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 – 2014-12-08T21:42:38.507

Hmm, so … another "useless use of cat". – isomorphismes – 2014-12-09T04:53:48.880

Not only, also a useless use of /dev/null. Amazed that despite my answer popularity, you still accept an answer that states "a set of simple commands" without pointing their unusefulness ... – jlliagre – 2014-12-09T06:06:16.357

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 – 2014-12-09T09:12:29.967

4@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 – 2014-12-09T09:36:34.317

6

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

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

Cyrus

Posted 2014-12-06T19:40:17.323

Reputation: 4 356

This syntax won't work in every shell. – reinierpost – 2014-12-10T11:04:41.010

2Correct. The question is only tagged with "bash". – Cyrus – 2014-12-10T11:06:52.347

@reinierpost It will work in all Bourne-style shells, won't it? Let's not worry about csh. – Barmar – 2014-12-12T19:20:05.353

: > messages also works. : or true are the more obvious choices for commands that print nothing and return true. – Peter Cordes – 2015-01-28T01:56:55.063

-3

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

echo -n > /var/log/messages

(Added -n to avoid the newline)

bbaassssiiee

Posted 2014-12-06T19:40:17.323

Reputation: 1 225

3This is indeed more comprehensible but unfortunately not a equivalent. It will even break functionalities like in the wtmp case. See my updated answer. – jlliagre – 2014-12-07T21:00:41.793

echo -n avoids newline. – bbaassssiiee – 2014-12-07T21:08:13.463

6It will indeed if you are sure to use bash, -n is otherwise not guaranteed to work in all Bourne shells. – jlliagre – 2014-12-07T21:10:14.647