Linux & Bash · Part I · Module 12 · Streams, Redirection and Pipes
Discarding Output, and /dev/null
Sometimes you do not want a command's output at all — you only want to know whether it worked. There is a file for that, and pointing a stream at it is trivial. Deciding which stream, and resisting the urge to silence both, is where the judgement lives.
Foundation15 min readLinuxPart IFundamentalsStreamsRedirection
Part I · Module 12 · Chapter 12.7 · Discarding Output, and /dev/null
Several chapters have ended commands with > /dev/null and moved on. Here is what that is.
1. A File That Keeps Nothing
$ echo "lots of text" > /dev/null
$ wc -c < /dev/null
0/dev/null is a special file that accepts any amount of data and stores none of it. Writing to it always succeeds and always discards. Reading from it gives immediate end-of-input.
It is a real entry in the filesystem:
$ ls -l /dev/null
crw-rw-rw- 1 root wheel 3, 2 Oct 8 11:02 /dev/nullThe c is the file type from Chapter 2.5 — a character device rather than an ordinary file. It is world-writable by design, and nothing accumulates, so there is no cleanup and no disk cost.
2. The Three Forms
command > /dev/null # discard results, keep errors visible
command 2> /dev/null # discard errors, keep results visible
command > /dev/null 2>&1 # discard bothMeasured:
$ ls /tmp /nope > /dev/null
ls: /nope: No such file or directory
$ ls /tmp /nope 2> /dev/null
/tmp:
agent.sock build scratch
$ ls /tmp /nope > /dev/null 2>&1
$The ordering rule from Chapter 12.3 applies unchanged: > /dev/null 2>&1 silences both, and 2>&1 > /dev/null silences only the results. &> /dev/null is the Bash shorthand for the first.
3. The Existence Check
By far the most common use, and worth recognising as an idiom rather than parsing each time:
command -v vcs > /dev/null 2>&1 || { echo "vcs not on PATH" >&2; exit 3; }Both streams are discarded because only the exit status matters. command -v prints the path when it finds something and says nothing when it does not — and you want neither.
The same shape appears everywhere:
grep -q ERROR run.log # -q already implies silence
diff -q a.txt b.txt > /dev/null # only "are they the same?"
ping -c1 buildhost > /dev/null 2>&1 # only "is it up?"
git diff --quiet # only "is anything changed?"4. Reading From It
$ wc -l < /dev/null
0Chapter 12.4 covered this: < /dev/null gives a command immediate end-of-input, which is the guard against an unattended job hanging on a prompt.
./possibly_interactive_tool < /dev/null > tool.log 2>&1Worth having on anything that runs in cron, in a regression harness, or over a connection you are about to close.
5. The Mistake
Silencing is easy. Silencing the wrong thing is the subject.
./run_sim.sh > /dev/null 2>&1That is a simulation whose output and error messages have both been thrown away. When it fails — and it will — there is nothing. No log, no message, no clue. The exit status is all you have, and Chapter 11.1 showed that several tools lie about it.
6. Send Them Somewhere Instead
The usual alternative to discarding errors is keeping them where nobody has to look unless something goes wrong:
./run_sim.sh > "$logdir/sim.log" 2> "$logdir/sim.err"
if [ -s "$logdir/sim.err" ]; then
echo "the simulation wrote to the error stream:" >&2
head -20 "$logdir/sim.err" >&2
fiNothing on your screen during a clean run, and everything available after a bad one. This is Chapter 12.3's separate-files pattern, and it is what people usually mean when they reach for 2>/dev/null.
And if the noise is a known, specific nuisance, filter it rather than silencing the channel:
./noisy_tool.sh 2>&1 | grep -v '^INFO:' | tee run.log7. The Other Device Files
/dev/null has a few relatives worth recognising:
| File | Does |
|---|---|
/dev/null | Discards writes; reads give end-of-input |
/dev/zero | Reads give an endless stream of zero bytes |
/dev/urandom | Reads give random bytes |
/dev/tty | Always your terminal, whatever the redirections |
/dev/stdout | Whatever stream two currently points at |
/dev/stderr | Whatever stream three currently points at |
/dev/tty appeared in Chapter 12.6; it is how you reach the terminal from inside a redirected pipeline.
/dev/stdout is occasionally the only way to make a tool that insists on a filename write to a stream:
some_tool --output /dev/stdout | grep ERROR/dev/urandom is the right source for anything security-related, as Chapter 8.5 noted when discussing $RANDOM:
head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n'8. In Practice
#!/bin/bash
set -uo pipefail
logdir="${1:?usage: $0 <logdir>}"
mkdir -p "$logdir" || { echo "cannot create $logdir" >&2; exit 2; }
# Status only — both streams discarded, deliberately.
command -v vcs > /dev/null 2>&1 || { echo "vcs not on PATH" >&2; exit 3; }
# Removing something that may not be there. The error is genuinely expected.
rm -f "$logdir/stale.lock" 2>/dev/null
# Real work: nothing discarded, errors kept separately, input closed.
./run_sim.sh < /dev/null > "$logdir/sim.log" 2> "$logdir/sim.err"
status=$?
# Known noise filtered; everything else kept and shown.
grep -v '^INFO:' "$logdir/sim.log" | tail -20
if [ -s "$logdir/sim.err" ]; then
echo "--- error stream ---" >&2
head -20 "$logdir/sim.err" >&2
fi
exit "$status"Four uses of /dev/null, each with a stated reason, and none of them on the command that does the work. That is the pattern worth copying: the checks are silenced and the work is recorded.
Practice
mkdir -p /tmp/dn && cd /tmp/dn1 — Confirm it keeps nothing.
echo "lots of text" > /dev/null
wc -c < /dev/null
ls -l /dev/null2 — Silence each stream in turn.
ls /tmp /nope > /dev/null
ls /tmp /nope 2> /dev/null | head -2
ls /tmp /nope > /dev/null 2>&1; echo " (silent, status $?)"3 — Confirm the ordering rule still applies.
ls /tmp /nope 2>&1 > /dev/null
echo " ^ the error still appeared — wrong order"4 — Use the existence idiom.
command -v bash > /dev/null 2>&1 && echo " bash found"
command -v nosuchtool > /dev/null 2>&1 || echo " nosuchtool not found"5 — Prefer a quiet flag.
printf 'a\nERROR\nb\n' > f.txt
grep -q ERROR f.txt && echo " grep -q: found"
grep ERROR f.txt > /dev/null && echo " redirect: found"6 — Give a command empty input.
wc -l < /dev/null7 — Filter noise instead of silencing the channel.
noisy() { echo "INFO: starting"; echo "real output"; echo "INFO: done"; echo "ERROR: bad" >&2; }
noisy 2>/dev/null
echo "--- vs ---"
noisy 2>&1 | grep -v '^INFO:'The first hid the error. The second kept it.
8 — Meet the relatives.
head -c 8 /dev/zero | od -An -tx1
head -c 8 /dev/urandom | od -An -tx1
echo "to the terminal regardless" > /dev/tty9 — Clean up. cd /tmp && rm -rf /tmp/dn
Check Your Understanding
1. What happens to data written to /dev/null, and what do you get reading from it?
2. What is the difference between cmd > /dev/null and cmd 2> /dev/null?
3. Why is command -v tool > /dev/null 2>&1 the right use and make 2>/dev/null the wrong one?
4. find / -name x 2>/dev/null hides the permission errors. What else does it hide?
5. When should you prefer grep -q to grep … > /dev/null?
6. You want a long run recorded but nothing on screen. Which form, and why not /dev/null?
9. Remember
/dev/nullaccepts any amount of data and keeps none. Reads from it give immediate end-of-input.- It is a real file — a character device, world-writable, with no disk cost.
> /dev/nulldiscards results;2> /dev/nulldiscards errors;> /dev/null 2>&1discards both.- The ordering rule still applies.
2>&1 > /dev/nullsilences only the results. cmd > /dev/null 2>&1is the existence-check idiom, where only the status carries information.- Prefer a tool's own quiet flag —
grep -q,diff -q,curl -s. It is clearer and often faster. < /dev/nullstops an unattended job hanging on a prompt.- Discard output freely; discard errors reluctantly. A silenced error is a bug met later with no information.
2>/dev/nullon a command that does real work is almost always wrong. Send errors to a file instead.- Filter known noise rather than silencing the channel:
2>&1 | grep -v PATTERN. /dev/ttyis always the terminal;/dev/stdoutis wherever stream two points;/dev/urandomis for anything security-related.- Silence the checks, record the work.
One question about pipelines has been raised three times and deferred each time. The last chapter of the module answers it: when a pipeline fails, how do you find out?
Where this fits
Part of the Linux & Bash curriculum.
