输出到 stderr 的回声

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

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

答案

您可以执行此操作,以方便阅读:

>&2 echo "error"

>&2文件描述符# >&2复制到文件描述符#1。因此,执行此重定向后,两个文件描述符都将引用同一文件: 最初引用的是一个文件描述符#2。有关更多信息,请参见《 Bash 黑客图解重定向教程》

您可以定义一个函数:

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

这将比脚本快,并且没有依赖性。

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

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

Glenn Jackman 的解决方案还避免了参数吞咽问题:

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

由于1是标准输出,因此您不必在输出重定向(例如>显式命名它,而只需键入:

echo This message goes to stderr >&2

由于您似乎担心1>&2难以可靠键入,因此消除冗余1可能会给您带来一点鼓励!

另外的选择

echo foo >>/dev/stderr

不,这是标准的方法。它不应该引起错误。

如果您不介意将消息也记录到 syslog 中,则 not_so_ugly 的方式是:

logger -s $msg

-s 选项的意思是:“将消息输出到标准错误以及系统日志中。”

这是一个简单的 STDERR 函数,它将管道输入重定向到 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

不要使用cat因为这里提到了一些catcat是一个程序,echoprintf是 bash(shell)内置printf 。启动程序或其他脚本(也在上文中提到)意味着要花所有的成本创建一个新的过程。使用内置函数,编写函数非常便宜,因为不需要创建(执行)进程(- 环境)。

操作员问 “是否有标准工具可将( 管道 )输出到 stderr”,schort 的回答是:NO ... 为什么? ... 在诸如 unix(Linux ...)之类的系统中,重新分配管道是一个基本概念,而 bash(sh)建立在这些概念之上。

我同意开场白的观点,即使用这样的符号进行重定向: &2>1对于现代程序员而言不是一件很愉快的事情,但这只是个 b 脚。 Bash 并非旨在编写庞大而强大的程序,而是旨在帮助管理员以更少的按键来实现工作;-)

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

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

注意:我是在回答帖子,而不是误导性 / 模糊的 “输出到 stderr 的回声” 问题(已由 OP 回答)。

使用函数显示意图并提供所需的实现。例如

#!/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!"

error_handling是:

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"; }

处理 OP 中问题的原因:

  • 最好的语法(有意义的单词而不是难看的符号)
  • 很难出错(尤其是如果您重复使用脚本)
  • 它不是标准的 Bash 工具,但可以是您或您的公司 / 组织的标准 Shell 库

其他原因:

  • 清晰 - 向其他维护者表明意图
  • 速度 - 函数比 shell 脚本快
  • 可重用性 - 一个函数可以调用另一个函数
  • 可配置性 - 无需编辑原始脚本
  • 调试 - 更容易找到导致错误的行(特别是如果您因大量重定向 / 过滤输出而陷入困境)
  • 健壮性 - 如果缺少某个函数并且您无法编辑脚本,则可以退回到使用具有相同名称的外部工具(例如,在 Linux 上可以将 log_error 别名为 logger)
  • 切换实现 - 您可以通过删除库的 “x” 属性来切换到外部工具
  • 输出不可知 - 您不再需要关心它是否进入 STDERR 或其他地方
  • 个性化 - 您可以使用环境变量配置行为

这已经得到了很多票的回答。仅作记录:

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

将有效地输出到stderr 。说明: /proc/self是当前进程的链接, /proc/self/fd保存进程打开的文件描述符。然后, 01 ,和2代表stdinstdoutstderr分别。

我发现它更具可读性。这在大多数 Linux 发行版中也可能有效:

echo "my errz" > /dev/stderr

使它更具可读性。