Hiding the output of a shell command usually involves redirecting stderr and stdout. Is there any builtin facility or command which by default hides the output but on error dumps all the accumulated output? I would like to run this as a wrapper for remote ssh commands. Now I have them using redirection but I don't get a clue as to what made them fail, and they are just too verbose.

EDIT: In the end I created the following template based on the answer by @Belmin which I tweaked a little bit to accumulate all the previous commands from the script, use the current process identifier, automatically remove the log, and add a failure red error message when something goes wrong. In this template the initial silent wrappers will succeed, then fail the third command because the directory already exists:


set -e

trap "/bin/rm -f $SILENT_LOG" EXIT

function report_and_exit {
    cat "${SILENT_LOG}";
    echo "\033[91mError running command.\033[39m"
    exit 1;

function silent {
    $* 2>>"${SILENT_LOG}" >> "${SILENT_LOG}" || report_and_exit;

silent mkdir -v pepe
silent mkdir -v pepe2
silent mkdir -v pepe
silent mkdir -v pepe2
  • 2
    If you redirect only stdout, stderr will still show up; is this sufficient for you, or do you want to see stdout as well if there's an error?
    – Kromey
    Commented Jun 25, 2014 at 16:19
  • I want to see both but only if something goes wrong, otherwise I don't want to see anything. Commented Jun 25, 2014 at 16:32
  • 2
    What I do is print stdout & stderr to a logfile so it doesn't clutter the screen. I also print stderr to the screen, so if there is and error I can see it. If I need details I can check the logfile, which contains the program output and the program errors in context. This way, I can 'see both but only if something goes wrong'. Does this help? See stackoverflow.com/questions/2871233/… Commented Jun 25, 2014 at 17:26
  • 1
    Is it safe to redirect stderr and stdout to the same file with two separate redirects? I thought we should always use 2>&1, something like: $* >>"${SILENT_LOG}" 2>&1" || report_and_exit
    – psmith
    Commented Feb 13, 2018 at 11:23

7 Answers 7


I'd setup a bash function like this:

function suppress
   /bin/rm --force /tmp/suppress.out 2> /dev/null; \
   ${1+"$@"} > /tmp/suppress.out 2>&1 || \
   cat /tmp/suppress.out; \
   bin/rm /tmp/suppress.out;

Then, you could just run the command:

suppress foo -a bar
  • An attacker who has non-root access on your system, could try to make a symlink between rm and command call, which would point to /etc/passswd or some other critical file and get the contents overwritten.
    – Mitar
    Commented Jun 18, 2017 at 18:55
  • 1
    BTW, order of redirects above should be: $* > /tmp/surpress.out 2>&1 This really captures the stderr.
    – Mitar
    Commented Jun 19, 2017 at 17:32
  • 2
    $* is not the best to handle arbitrary input. Especially when it contains spaces or flags. Most portable is ${1+"$@"} according to stackoverflow.com/questions/743454/…
    – balrok
    Commented Oct 17, 2017 at 13:38
  • Modified per both comments. Thanks---good info. Commented Oct 18, 2017 at 14:37
  • Spelling merriam-webster.com/dictionary/suppress
    – Hatshepsut
    Commented Mar 5, 2018 at 19:45

It should be easy enough to write a script for this purpose.

Something like this completely untested script.

program_we_want_to_capture &2>1 > $OUTPUT
[ $? -ne 0 ]; then
    cat $OUTPUT
    exit 1

On the other hand for commands I run as part of a script I usually want something better than simply print all the output. I often limit what I see to the unknown. Here is a script I adapted from something I read over a decade ago.


the_command 2>&1 | awk '
  # Initialize our error-detection flag.
  ErrorDetected = 0
# Following are regex that will simply skip all lines
# which are good and we never want to see
/ Added UserList source/ || \
/ Added User/ || \
/ init domainlist / || \
/ init iplist / || \
/ init urllist / || \
/ loading dbfile / || \
/^$/ {next} # Uninteresting message.  Skip it.

# Following are lines that we good and we always want to see
/ INFO: ready for requests / \
  print "  " $0 # Expected message we want to see.

# any remaining lines are unexpected, and probably error messages.  These will be printed out and highlighted.
  print "->" $0 # Unexpected message.  Print it

  if (ErrorDetected == 1) {
    print "Unexpected messages (\"->\") detected in execution."
    exit 2
exit $?

Don't reinvent the wheel on this one. It's a common problem, notably with cron jobs, which is why chronic was created. You can likely install it from your package manager. Check the moreutils package or just run chronic ls and your shell should tell you what package to install. The usage is as simple as this:

chronic noisy_command --some-option an-arg

It will suppress all output unless the command fails.

There is also cronic but it has a slight difference: it "defines an error as any non-trace error output or a non-zero result code." So even if your command succeeds, any write to stderr will cause output (thus mail from a cron job). This is why I generally prefer chronic.

You can always install both and choose whichever fits a task best.

  • I don't see it on Ubuntu 18.04. Commented Aug 23, 2021 at 1:09
  • @MattAlexander It's there for me. Have you enabled the universe source for apt?
    – Walf
    Commented Aug 23, 2021 at 1:47
  • You are correct, I was mistaken. Commented Aug 23, 2021 at 3:33

I don't think there is a clean way of doing this, the only thing I can think of is

  • Capture the output of the command.
  • Check the return value of the command and if it failed
    • display the captured output.

Implementing this might though be a interesting project but perhaps beyond Q&A.

  • Should be doable with a function. Hm, let me give it a try. Commented Jun 25, 2014 at 17:43
  • cronic does exactly this and existed at least 7 years before your answer.
    – Walf
    Commented Apr 7, 2022 at 8:09

Try so:

out=`command args...` || echo $out
  • 3
    I'd write it as out="$(command args...)" || echo "$out"
    – kasperd
    Commented Jun 26, 2014 at 13:38
  • This only deals with STDOUT, not STDERR, where most error messages, and many info/warning messages are printed. A simple demonstration of this is define a shell function that prints to STDERR function foobar { >&2 echo "$@" } then use it in your one-liner out="$(foobar x y z)" || echo "$out". You can see that the exit code ($?) is true, but it still produces output.
    – Walf
    Commented Nov 9, 2021 at 23:34
  • Using it in a script to check if the k8s-cluster is accessible: versioncheck=$(kubectl version 2>&1 ) || { echo "Something is wrong with your kubectl configuration. Are you logged in?"; echo "$versioncheck"; exit 1; }
    – blaimi
    Commented Jan 16, 2023 at 11:58

going short with something like tehcommand &>/tmp/$$ || cat /tmp/$$

depends how much usability/typing you want/need. (e.g. using it as a pipe or passing the command by argument)

@zoredache short script is basically a proto-wrapper for this, which would give more robustness, handle concurrency, etc


Based on @Belmin Fernandez' answer, I wrote a version that uses an secure, non-world-readable file location (so multiple instances of this script can run at the same time without race condition). It also logs the exit code.

function suppress
   ${1+"$@"} > "$TMP" 2>&1 || ( echo "$* exited with $?" && cat "$TMP" )
   rm "$TMP"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .