Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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:

#!/bin/sh

set -e

SILENT_LOG=/tmp/silent_log_$$.txt
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
share|improve this question
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 Jun 25 at 16:19
    
I want to see both but only if something goes wrong, otherwise I don't want to see anything. –  Grzegorz Adam Hankiewicz Jun 25 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/… –  Stefan Lasiewski Jun 25 at 17:26

5 Answers 5

up vote 2 down vote accepted

I'd setup a bash function like this:

function surpress { /bin/rm --force /tmp/surpress.out 2> /dev/null; $* 2>&1 > /tmp/surpress.out || cat /tmp/surpress.out; /bin/rm /tmp/surpress.out; }

Then, you could just run the command:

surpress foo -a bar

Hope this helps!

share|improve this answer
    
Oh, forgot to remove the test echo command. This should work now. –  Belmin Fernandez Jun 25 at 17:41

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.

share|improve this answer
    
Should be doable with a function. Hm, let me give it a try. –  Belmin Fernandez Jun 25 at 17:43

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

Something like this completely untested script.

OUTPUT=`tempfile`
program_we_want_to_capture &2>1 > $OUTPUT
[ $? -ne 0 ]; then
    cat $OUTPUT
    exit 1
fi
rm $OUTPUT

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.

#!/bin/bash

the_command 2>&1 | awk '
BEGIN \
{
  # 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.
  next
}

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

END \
{
  if (ErrorDetected == 1) {
    print "Unexpected messages (\"->\") detected in execution."
    exit 2
  }
}
'
exit $?
share|improve this answer

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

share|improve this answer

Try so:

out=`command args...` || echo $out
share|improve this answer
    
I'd write it as out="$(command args...)" || echo "$out" –  kasperd Jun 26 at 13:38

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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