2023-03-22 10:00:09

输出到stderr的echo

是否有一个标准的Bash工具,其行为类似于echo,但输出到stderr而不是stdout?

我知道我可以做echo foo 1>&2,但它有点难看,而且,我怀疑,容易出错(例如,当事情发生变化时,更容易编辑错误)。


当前回答

read是一个shell内置命令,可打印到stderr,可以像echo一样使用,而无需执行重定向技巧:

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

-t 0.1是一个超时,它禁用读取的主要功能,将一行stdin存储到变量中。

其他回答

您可以定义函数:

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

这将比脚本更快,并且没有依赖关系。

卡米洛·马丁的bash特定建议使用“here字符串”,并将打印传递给它的任何内容,包括echo通常会接受的参数(-n):

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

格伦·杰克曼的解决方案也避免了吞论点的问题:

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

你可以这样做,这有助于阅读:

>&2 echo "error"

>&2将文件描述符#2复制到文件描述符#1。因此,执行此重定向后,两个文件描述符将引用同一个文件:最初引用的是一个文件描述符#2。有关更多信息,请参阅Bash Hackers Illustrated redirection Tutorial。

James Roth和Glenn Jackman建议的组合解决方案

添加ANSI颜色代码以红色显示错误消息:

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"

不要像这里提到的那样使用猫。cat是一个程序而echo和printf是bash(shell)内置的。启动一个程序或另一个脚本(如上所述)意味着创建一个新的过程,并承担所有成本。使用内置函数,编写函数非常便宜,因为不需要创建(执行)进程(-environment)。

开场白询问“是否有任何标准工具可以输出(管道)到stderr”,简短的回答是:否。。。为什么?重定向管道是unix(Linux…)和bash(sh)等系统中的一个基本概念。

我同意开场白的观点,即用这样的符号重定向:&2>1对现代程序员来说不是很愉快,但这就是bash。Bash不是为了编写庞大而健壮的程序,而是为了帮助管理员以更少的按键完成工作;-)

至少,您可以将重定向放置在行中的任何位置:

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

这里有一个函数用于检查最后一个命令的退出状态,显示错误并终止脚本。

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
}

用法:

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

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

该函数打印脚本名称和日期,以便在从crontab调用脚本并记录错误时有用。

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