echo输出到stderr

BCS*_*BCS 1026 bash

是否有一个标准的Bash工具,它像echo一样输出到stderr而不是stdout?

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

Mar*_*lio 1321

这个问题很旧,但你可以做到这一点,这有助于阅读:

>&2 echo "error"
Run Code Online (Sandbox Code Playgroud)

运算符>&2字面意思是将文件描述符1(>&2)的地址重定向到该>&2命令1的文件描述符2()的地址.根据您想要了解它的深度,请阅读:http://wiki.bash-hackers.org/howto/redirection_tutorial

为避免与其他重定向的交互,请使用subshel​​l

>&2 echo "error"
Run Code Online (Sandbox Code Playgroud)

1将>&2文件描述符#2复制到文件描述符#1.因此,在执行此重定向之后,两个文件描述符将引用相同的文件:一个文件描述符#2 最初是指.

  • 在我使用类Unix系统近40年的时间里,我从未想过你可以将重定向放在任何地方但最后.像这样把它放在前面使得它更加明显(或者像@MarcoAurelio所说的那样"便于阅读").给我一些新的东西+1. (134认同)
  • @BCS我不知道在shell脚本中使用`alias`.使用`errcho(){>&2 echo $ @可能更安全; }` (42认同)
  • >&2 通常放在最后。这会起作用,但它的使用频率较低 (7认同)
  • 我总是很难理解如何读取 bash 重定向,但我想我终于找到了读取它们的正确方法:重要的是要注意 1 和 2 文件描述符已经指向某个地方,所以当你写 `2>&1` 时表示“点 2,其中 1 _当前_指向”,所以现在如果您错误地写入“2>&1 >文件”,它会读取“点 2,其中 1 已经指向文件,并且点 1 指向文件”,因此 2 现在位于 1 曾经指向的位置go 但 1 不再去那里...相反, `>file 2>&1` 读取 `point 1 到此文件,point 2 到 1 当前指向的位置`。因此“&”可以读作“where”。 (4认同)
  • 我很久以前就学会了这个技巧。这个页面有一些很好的信息。http://www.tldp.org/LDP/abs/html/io-redirection.html (3认同)

Jam*_*oth 403

你可以定义一个函数:

echoerr() { echo "$@" 1>&2; }
echoerr hello world
Run Code Online (Sandbox Code Playgroud)

这比脚本更快,没有依赖性.

Camilo Martin的bash特定建议使用"here string"并将打印传递给它的任何内容,包括echo通常会吞下的参数(-n):

echoerr() { cat <<< "$@" 1>&2; }
Run Code Online (Sandbox Code Playgroud)

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

echoerr() { printf "%s\n" "$*" >&2; }
Run Code Online (Sandbox Code Playgroud)

  • 哦,你实际上也可以使用猫:`echoerr(){cat <<<"$ @"1>&2; }` (10认同)
  • 我必须说回声有点不可靠.`echoerr -ne xt`不会打印"-ne xt".更好地使用`printf`. (6认同)
  • 或者,`printf"%s \n""$*">&2` (4认同)
  • @GKFX当然它只能在引用时正常工作.为什么人们不引用他们的字符串超出了我.(当你不引用时,由一个或多个`$ IFS`空格分隔的所有内容都作为一个单独的参数发送,在`echo`的情况下,它意味着将它们连接到`0x20`s,但是没有引用远的危险超重2个字符的便利性类型). (4认同)
  • 我没有意识到这一点.添加. (2认同)
  • @GKFX不,不,`echoerr'foo bar'`在`foo`和`bar`之间会有两个空格.*(我必须添加一个零宽度的连接器,使其在此注释中显示两个空格,因此不要复制和粘贴它,否则它将在控制台中有三个空格).* (2认同)
  • @GKFX 这是一个常见的错误(不幸的是)。在这方面,当您不想解释任何内容时,请记住使用单引号(不仅仅是 `$variables`,还要考虑 `echo "why!?"` 与 `echo 'why!?'`,另请注意“echo '\'”是如何正确的)。一旦你记住了这些东西,Bash 就很美丽,但它会因为对其特性和它们引起的错误的误解而受到阻碍(与 Javascript 发生的情况相同,它[已经走了很长一段路](http://es6-features .org),但仍然被那些第一印象不好的人所回避)。 (2认同)

Bra*_*des 235

由于1是标准输出,因此您不必在输出重定向之前明确地命名它,>而是可以简单地键入:

echo This message goes to stderr >&2

由于您似乎担心1>&2难以可靠地打字,因此消除冗余1可能会给您带来轻微的鼓励!

  • 我相信如果你想添加空格,`&gt;&amp; 2`应该可以工作。 (5认同)
  • @knocte 这没有什么区别,因为 `2` 是一个打开的文件句柄,而不是路径 (3认同)
  • 只是为了我自己注意 - `&gt; &amp;2` 不起作用,那里不允许有空格:) (2认同)

小智 53

另外一个选项

echo foo >>/dev/stderr
Run Code Online (Sandbox Code Playgroud)

  • 如果执行此行的脚本 - 让我们称之为`foo` - 有自己的stderr重定向 - 例如`foo> foo.log 2>&1` - 那么`echo foo>/dev/stderr`会破坏它之前的所有输出.应该使用`>>`:`echo foo >>/dev/stderr` (11认同)
  • 它在某些无法访问/ dev/stderr的chroot中不起作用. (6认同)
  • 这个选项是否可移植?有人知道这不适用于某些unix风味吗? (3认同)

Mat*_*hen 31

不,这是执行此操作的标准方法.它不应该导致错误.

  • 恕我直言,如果有人混淆代码并且不知道bash,这可能是你的问题中最少的. (27认同)
  • *它*不应该导致错误,但我可能更有可能.OTOH,这不是什么大不了的事. (8认同)
  • 我认为如果这可能是一个问题,你应该开始使用另一种语言:试图使bash万无一失是一个傻瓜的冒险. (7认同)
  • @Mike DeSimone:如果其他人对代码混淆,在输出​​周围混乱,并且实际上不知道bash,他们可能很容易丢弃(或错误)`1>&2`.我们都希望这不会发生,但我相信我们一直都是这样做的地方. (6认同)
  • `(echo something 1>&2;还有别的东西)> log` - >`(回显一些东西; cp一些垃圾1>&2;别的东西)> log`糟糕. (2认同)

Grz*_*ywo 15

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

logger -s $msg
Run Code Online (Sandbox Code Playgroud)

-s选项表示:"将消息输出到标准错误以及系统日志."

  • 这很棒!它有多便携? (4认同)
  • @code_monk:logger 命令预计与 IEEE Std 1003.2(“POSIX.2”)兼容,logger 命令是 util-linux 包的一部分,可从 Linux Kernel Archive ⟨https://www.kernel.org /pub/linux/utils/util-linux/⟩. (3认同)

小智 12

这是一个简单的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
Run Code Online (Sandbox Code Playgroud)

  • 我认为您可以使用别名做同样的事情,并且要紧凑得多 (2认同)

ret*_*n42 8

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

The opner asks "is there any standard tool to output (pipe) to stderr", the schort answer is : NO ... why? ... rediredcting pipes is an elemantary 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
Run Code Online (Sandbox Code Playgroud)

  • 仅仅因为性能原因告诉开发人员不要使用程序是过早的优化。优雅、易于遵循的方法应该优先于难以理解的执行更好的代码(以毫秒为单位)。 (4认同)
  • 让某人知道 Bash 内置函数与 `cat` 的性能权衡与指示某人不要使用 cat 因为它很慢是有区别的。有无数用例中 cat 是正确的选择,所以这就是我反对您的答案的原因。 (2认同)

Cez*_*ski 8

注意:我正在回答帖子 - 而不是误导/模糊的"输出到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!"
Run Code Online (Sandbox Code Playgroud)

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"; }
Run Code Online (Sandbox Code Playgroud)

处理OP问题的原因:

  • 最好的语法可能(有意义的单词而不是丑陋的符号)
  • 更难出错(特别是如果你重用脚本)
  • 它不是标准的Bash工具,但它可以是您或您的公司/组织的标准shell库

其他原因:

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


Seb*_*ian 8

这已经得到了很好的回答.仅供记录:

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

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

我发现它更具可读性.这也适用于大多数Linux分发:

echo "my errz" > /dev/stderr

使它更具可读性.

  • `/ proc/self/fd/*`在Android上的Termux上可用,但不在`/ dev/stderr`上. (3认同)
  • / proc / self链接在MacOS上不起作用,因此我会坚持使用更直接的`/ dev / stderr`方法。另外,如其他答案/评论中所述,最好使用`&gt;&gt;`附加。 (2认同)

n0r*_*0rd 5

制作脚本

#!/bin/sh
echo $* 1>&2
Run Code Online (Sandbox Code Playgroud)

那将是你的工具。

或者,如果您不想在单独的文件中包含脚本,则创建一个函数。

  • 最好将其作为一个函数(就像詹姆斯·罗斯的答案),并且最好传递所有参数,而不仅仅是第一个参数。 (6认同)
  • @OgrePsalm33 函数更好的一个原因是,在调用脚本时,通常会创建一个新的 shell 实例来提供执行脚本的环境。另一方面,函数被放置到当前运行的 shell 环境中。在这种情况下,调用函数将是一种更有效的操作,因为可以避免创建另一个 shell 实例。 (5认同)
  • 为什么函数会更好?(或者,或者:“最好解释一下为什么会更好......”) (2认同)

Dou*_*yle 5

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

read -t 0.1 -p "This will be sent to stderr"
Run Code Online (Sandbox Code Playgroud)

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

  • OS X上的Bash不允许"0.1" (4认同)

Guy*_*ock 5

我最近偶然发现的另一个选择是:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2
Run Code Online (Sandbox Code Playgroud)

这仅使用Bash内置函数,同时使多行错误输出的出错率降低(因为您不必记住要添加&>2到每一行)。

  • @return42我否决了你的答案,因为它所做的只是告诉OP没有比他们开始的更好的答案了..这不是真正的答案。我在您的答案中也没有看到子外壳建议...您的答案实际上只是建议OP不要使用“cat”或任何其他实用程序,这与问题无关。 (2认同)

Pol*_*ase 5

James RothGlenn 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"
Run Code Online (Sandbox Code Playgroud)