BCS
BCS

Reputation: 78506

echo that outputs to stderr

Is there a standard Bash command that acts like echo but outputs to stderr rather than stdout?

I know I can do echo foo 1>&2 but it's kinda ugly and, I suspect, error-prone (e.g. more likely to get edited wrong when things change).

Upvotes: 1660

Views: 1007132

Answers (15)

Marco Aurelio
Marco Aurelio

Reputation: 22126

You could do this, which facilitates reading:

>&2 echo "error"

>&2 copies file descriptor #2 to file descriptor #1. Therefore, after this redirection is performed, both file descriptors will refer to the same file: the one file descriptor #2 was originally referring to. For more information see the Bash Hackers Illustrated Redirection Tutorial.

Upvotes: 2170

Brandon Rhodes
Brandon Rhodes

Reputation: 89325

Since 1 is the standard output, you do not have to explicitly name it in front of an output redirection like >. Instead, you can simply type:

echo This message goes to stderr >&2

Since you seem to be worried that 1>&2 will be difficult for you to reliably type, the elimination of the redundant 1 might be a slight encouragement to you!

Upvotes: 475

return42
return42

Reputation: 561

Don't use cat as some have mentioned here. cat is a program while echo and printf are bash (shell) builtins. Launching a program or another script (also mentioned above) means to create a new process with all its costs. Using builtins, writing functions is quite cheap, because there is no need to create (execute) a process (-environment).

The opener asks "is there any standard tool to output (pipe) to stderr", the short answer is : NO ... why? ... redirecting pipes is an elementary concept in systems like unix (Linux...) and bash (sh) builds up on these concepts.

I agree with the opener that redirecting with notations like this: &2>1 is not very pleasant for modern programmers, but that's bash. Bash was not intended to write huge and robust programs, it is intended to help the admins to get there work with less keypresses ;-)

And at least, you can place the redirection anywhere in the line:

$ echo This message >&2 goes to stderr 
This message goes to stderr

Upvotes: 16

Miroslav Popov
Miroslav Popov

Reputation: 3383

Here is a function for checking the exit status of the last command, showing error and terminate the script.

or_exit() {
    local exit_status=$?
    local message=$*

    if [ "$exit_status" -gt 0 ]
    then
        echo "$(date '+%F %T') [$(basename "$0" .sh)] [ERROR] $message" >&2
        exit "$exit_status"
    fi
}

Usage:

gzip "$data_dir"
    or_exit "Cannot gzip $data_dir"

rm -rf "$junk"
    or_exit Cannot remove $junk folder

The function prints out the script name and the date in order to be useful when the script is called from crontab and logs the errors.

59 23 * * * /my/backup.sh 2>> /my/error.log

Upvotes: 5

Polymerase
Polymerase

Reputation: 6781

Combining solution suggested by James Roth and Glenn Jackman

  • add ANSI color code to display the error message in red:
echoerr() { printf "\e[31;1m%s\e[0m\n" "$*" >&2; }

# if somehow \e is not working on your terminal, use \u001b instead
# echoerr() { printf "\u001b[31;1m%s\u001b[0m\n" "$*" >&2; }

echoerr "This error message should be RED"

Upvotes: 13

Sebastian
Sebastian

Reputation: 5835

My suggestion:

echo "my errz" >> /proc/self/fd/2

or

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2 will effectively output to stderr because /proc/self is a link to the current process, and /proc/self/fd holds the process opened file descriptors, and then, 0, 1, and 2 stand for stdin, stdout and stderr respectively.

The /proc/self link doesn't work on MacOS, however, /proc/self/fd/* is available on Termux on Android, but not /dev/stderr. How to detect the OS from a Bash script? can help if you need to make your script more portable by determining which variant to use.

Upvotes: 18

GuyPaddock
GuyPaddock

Reputation: 2517

Another option that I recently stumbled on is this:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2

This uses only Bash built-ins while making multi-line error output less error prone (since you don't have to remember to add &>2 to every line).

Upvotes: 27

Zombo
Zombo

Reputation: 1

Another option

echo foo >>/dev/stderr

Upvotes: 86

Cezary Baginski
Cezary Baginski

Reputation: 2095

Note: I'm answering the post- not the misleading/vague "echo that outputs to stderr" question (already answered by OP).

Use a function to show the intention and source the implementation you want. E.g.

#!/bin/bash

[ -x error_handling ] && . error_handling

filename="foobar.txt"
config_error $filename "invalid value!"

output_xml_error "No such account"

debug_output "Skipping cache"

log_error "Timeout downloading archive"

notify_admin "Out of disk space!"

fatal "failed to open logger!"

And error_handling being:

ADMIN_EMAIL=root@localhost

config_error() { filename="$1"; shift; echo "Config error in $filename: $*" 2>&1; }

output_xml_error() { echo "<error>$*</error>" 2>&1; }

debug_output() { [ "$DEBUG"=="1" ] && echo "DEBUG: $*"; }

log_error() { logger -s "$*"; }

fatal() { which logger >/dev/null && logger -s "FATAL: $*" || echo "FATAL: $*"; exit 100; }

notify_admin() { echo "$*" | mail -s "Error from script" "$ADMIN_EMAIL"; }

Reasons that handle concerns in OP:

  • nicest syntax possible (meaningful words instead of ugly symbols)
  • harder to make an error (especially if you reuse the script)
  • it's not a standard Bash tool, but it can be a standard shell library for you or your company/organization

Other reasons:

  • clarity - shows intention to other maintainers
  • speed - functions are faster than shell scripts
  • reusability - a function can call another function
  • configurability - no need to edit original script
  • debugging - easier to find the line responsible for an error (especially if you're deadling with a ton of redirecting/filtering output)
  • robustness - if a function is missing and you can't edit the script, you can fall back to using external tool with the same name (e.g. log_error can be aliased to logger on Linux)
  • switching implementations - you can switch to external tools by removing the "x" attribute of the library
  • output agnostic - you no longer have to care if it goes to STDERR or elsewhere
  • personalizing - you can configure behavior with environment variables

Upvotes: 21

James
James

Reputation: 7198

You could define a function:

echoerr() { echo "$@" 1>&2; }
echoerr hello world

This would be faster than a script and have no dependencies.

Camilo Martin's bash specific suggestion uses a "here string" and will print anything you pass to it, including arguments (-n) that echo would normally swallow:

echoerr() { cat <<< "$@" 1>&2; }

Glenn Jackman's solution also avoids the argument swallowing problem:

echoerr() { printf "%s\n" "$*" >&2; }

Upvotes: 548

Grzegorz Luczywo
Grzegorz Luczywo

Reputation: 10492

If you don't mind logging the message also to syslog, the not_so_ugly way is:

logger -s $msg

The -s option means: "Output the message to standard error as well as to the system log."

Upvotes: 34

Douglas Mayle
Douglas Mayle

Reputation: 21747

read is a shell builtin command that prints to stderr, and can be used like echo without performing redirection tricks:

read -t 0.1 -p "This will be sent to stderr"

The -t 0.1 is a timeout that disables read's main functionality, storing one line of stdin into a variable.

Upvotes: 6

erselbst
erselbst

Reputation: 161

This is a simple STDERR function, which redirect the pipe input to STDERR.

#!/bin/bash
# *************************************************************
# This function redirect the pipe input to STDERR.
#
# @param stream
# @return string
#
function STDERR () {

cat - 1>&2

}

# remove the directory /bubu
if rm /bubu 2>/dev/null; then
    echo "Bubu is gone."
else
    echo "Has anyone seen Bubu?" | STDERR
fi


# run the bubu.sh and redirect you output
tux@earth:~$ ./bubu.sh >/tmp/bubu.log 2>/tmp/bubu.err

Upvotes: 10

n0rd
n0rd

Reputation: 12610

Make a script

#!/bin/sh
echo $* 1>&2

that would be your tool.

Or make a function if you don't want to have a script in separate file.

Upvotes: 5

Matthew Flaschen
Matthew Flaschen

Reputation: 284786

No, that's the standard way to do it. It shouldn't cause errors.

Upvotes: 40

Related Questions