Answers:
您可以执行此操作,以方便阅读:
>&2 echo "error"
>&2
将文件描述符#2复制到文件描述符#1。因此,执行此重定向后,两个文件描述符都将引用同一文件:最初引用了一个文件描述符#2 。有关更多信息,请参见《Bash黑客图解重定向教程》。
alias
在shell脚本中使用。或许,这将是更安全的使用errcho(){ >&2 echo $@; }
errcho(){ >&2 echo $@|pr -To5;}
将无法正常工作。要执行类似的操作,您必须将重定向放置在最后一个管道之后,例如:errcho(){ echo $@|>&2 pr -To5;}
您可以定义一个函数:
echoerr() { echo "$@" 1>&2; }
echoerr hello world
这将比脚本快,并且没有依赖性。
卡米洛·马丁(Camilo Martin)的bash特定建议使用“此处字符串”,并将打印您传递给它的任何内容,包括回显通常会吞咽的参数(-n):
echoerr() { cat <<< "$@" 1>&2; }
Glenn Jackman的解决方案还避免了参数吞咽问题:
echoerr() { printf "%s\n" "$*" >&2; }
echoerr -ne xt
不会打印“ -ne xt”。更好地使用printf
它。
echoerr() { cat <<< "$@" 1>&2; }
printf "%s\n" "$*" >&2
$IFS
空格分隔的所有内容将作为一个单独的参数发送,在这种情况下,echo
意味着将它们与0x20
s 相连,但是如果不加引号,则很可能会浪费太少的两个字符) 。
由于1
是标准输出,因此您不必在输出重定向之前显式命名它,>
而只需键入:
echo此消息转到stderr>&2
由于您似乎担心1>&2
很难进行可靠的键入,因此消除冗余1
可能会给您带来一点鼓励!
另外一个选项
echo foo >>/dev/stderr
foo
具有自己的stderr重定向(例如foo >foo.log 2>&1
-),则echo foo >/dev/stderr
它将覆盖之前的所有输出。 >>
应该改为使用:echo foo >>/dev/stderr
/dev/fd/2
。
/proc/self/fd/2
。请参阅下面的回答:)
不,这是标准的方法。它不应该引起错误。
1>&2
。我们都希望不会发生这种情况,但是我敢肯定,我们到过的地方都有。
( echo something 1>&2 ; something else ) > log
-> (echo something; cp some junk 1>&2 ; something else) > log
糟糕。
如果您不介意将消息也记录到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
echo what | /dev/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中问题的原因:
其他原因:
我的建议:
echo "my errz" >> /proc/self/fd/2
要么
echo "my errz" >> /dev/stderr
echo "my errz" > /proc/self/fd/2
将有效输出stderr
,因为/proc/self
是当前进程的链接,并/proc/self/fd
持有进程打开的文件描述符,然后0
,1
和2
代表stdin
,stdout
并stderr
分别。
该/proc/self
链接在MacOS /proc/self/fd/*
上不起作用,但是可在Android上的Termux上使用,但不能使用/dev/stderr
。如何从Bash脚本检测操作系统?如果需要通过使用哪种变体来使脚本更易于移植,可以提供帮助。
/proc/self
链接在MacOS上不起作用,因此我会坚持使用更简单的/dev/stderr
方法。另外,如其他答案/评论中所述,最好使用>>
追加。
/proc/self/fd/*
在Android上的Termux上可用,但不可用/dev/stderr
。
不要使用,cat
因为这里提到了一些。cat
是
while 的程序echo
,printf
是bash(shell)内置函数。启动程序或其他脚本(也在上面提到)意味着要花所有的成本创建一个新的过程。使用内置函数,编写函数非常便宜,因为不需要创建(执行)进程(-环境)。
操作者问“是否有标准工具可将(管道)输出到stderr”,schort的回答是:NO ...为什么?...重新分配管道是unix(Linux ...)等系统中的一个基本概念,而bash(sh)建立在这些概念上。
我同意开场白,即用这样的符号进行重定向:&2>1
对于现代程序员来说不是很令人愉快,但这是个b脚。Bash并不是要编写庞大而健壮的程序,而是要帮助管理员以更少的按键来实现工作;-)
至少,您可以将重定向放置在行中的任何位置:
$ echo This message >&2 goes to stderr
This message goes to stderr
cat
与指示某人不要使用cat(因为它很慢)之间有区别。在无数用例中,cat是正确的选择,所以这就是为什么我反对您的答案。
echo
更换。即使使用cat
,他也必须使用bash重定向。无论如何。因此,这里绝对没有意义cat
。顺便说一句,我cat
每天使用100次,但是在这种情况下,开瓶器从来没有要求...您知道吗?
我最近偶然发现的另一个选择是:
{
echo "First error line"
echo "Second error line"
echo "Third error line"
} >&2
这仅使用Bash内置函数,同时使多行错误输出的错误发生率降低(因为您不必记住要添加&>2
到每一行)。
cat
或使用任何其他实用程序,这对这个问题来说是不合时宜的。
read
是shell内置命令,可打印到stderr,可以像echo一样使用,而无需执行重定向技巧:
read -t 0.1 -p "This will be sent to stderr"
这-t 0.1
是一个超时,它禁用了read的主要功能,将一行stdin存储到一个变量中。
制作脚本
#!/bin/sh
echo $* 1>&2
那将是您的工具。
或者,如果您不想在单独的文件中包含脚本,请创建函数。
Mac OS X:我尝试了接受的答案以及其他几个答案,所有这些导致我在Mac上编写了STDOUT而不是STDERR。
这是使用Perl写入标准错误的可移植方法:
echo WARNING! | perl -ne 'print STDERR'