Stop using /dev/null

· Byron Torres

When you want to silence the output of a shell command, use the following POSIX syntax:

$ command n>&-          # this
$ command n>/dev/null   # NOT this

Ex: Silence the stderr output (file descriptor 2) of ls:

$ ls . /root         # will print error
$ ls . /root 2>&-    # will NOT print error

Ex: Silence the stdout output (fd 1) of ping (only print errors):

$ ping fediverse.party >&-

Ex: Silence file permission errors from grep:

$ grep -r power /sys/ 2>&-

Ex: Silence all output of curl:

$ curl -v https://fediverse.party  >&- 2>&-

This syntax is defined in POSIX, is more concise and expressive, and does not require you to open a new file descriptor for /dev/null. It simply closes the specified file descriptor. I believe /dev/null is one of the few files mandated by POSIX, but I think most will agree that n>&- beats /dev/null by virtue of simplicity.

If you’re learning shell and don’t know what /dev/null is, /dev/null is a virtual device file provided by the Linux operating system, which discards anything written to it, behaving as a data blackhole. It’s therefore often used to write the undesirable output of commands into. However, /dev/null is often not necessary and the builtin n>&- syntax seems to have been forgotten. So I’m making an effort to spread the word.

Bonus link: shellhaters.org - An excellent handbook for POSIX shell and utilities.

Real example

I use this trick in my shell dotfiles. I have a shell script I run to print pretty, informational git commands within the current git repository. However, I need to know whether I’m in a child directory of a git repository, else any git commands my script runs will fail verbosely instead. So, I wrote this in my script (full script):

git log -0 2>&- && {
    git log -1 --abrev-commit --format=short --color --decorate \
    | sed -n '1p; /^    /p'
    git status -s
    echo
}

With the -0 option, git does not print to stdout, but will print an error to stderr if I’m not in a git repository. 2>&- silences stderr, so then I can use the exit code with && to run other git commands safely when I am in a repo.

Case for /dev/null

There are times when /dev/null is better. Ex: Timing the download of a website using curl’s default progress meter:

$ curl https://fediverse.party/ >&-         # complains it can't write
curl: (23) Failure writing output to destination
$ curl https://fediverse.party/ >/dev/null  # writes quietly

Your duty

You are now enlightened, and duty bound to enlighten others. Share this with your unenlighted friends, and stop the proliferation of bloated shell scripts around the world.

Or email me to contribute to this article.