【发布时间】:2011-02-28 17:51:59
【问题描述】:
是否有标准的 Bash 工具,其作用类似于 echo,但输出到 stderr 而不是 stdout?
我知道我可以做到echo foo 1>&2,但它有点难看,而且我怀疑容易出错(例如,当事情发生变化时更有可能被编辑错误)。
【问题讨论】:
标签: bash
是否有标准的 Bash 工具,其作用类似于 echo,但输出到 stderr 而不是 stdout?
我知道我可以做到echo foo 1>&2,但它有点难看,而且我怀疑容易出错(例如,当事情发生变化时更有可能被编辑错误)。
【问题讨论】:
标签: bash
你可以这样做,方便阅读:
>&2 echo "error"
>&2 将文件描述符#2 复制到文件描述符#1。因此,执行此重定向后,两个文件描述符将引用同一个文件:一个文件描述符#2 最初引用。如需更多信息,请参阅Bash Hackers Illustrated Redirection Tutorial。
【讨论】:
alias。使用errcho(){ >&2 echo $@; } 可能会更安全
2>&1它意味着point 2 where 1 is _currently_ pointing to所以现在如果你写错了2>&1 >file,它读为point 2 where 1 is already going and point 1 to a file所以2现在去1过去的地方但1不再去那里......相反>file 2>&1读point 1 to this file and point 2 to where 1 is currently pointing to。 & 因此可以读作where。
你可以定义一个函数:
echoerr() { echo "$@" 1>&2; }
echoerr hello world
这将比脚本更快,并且没有依赖关系。
Camilo Martin 的 bash 特定建议使用“here 字符串”,并将打印您传递给它的任何内容,包括 echo 通常会吞下的参数 (-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 的情况下,这意味着将它们与 0x20s 连接起来,但不引用的危险远远超过减少 2 个字符的便利性)。
由于1 是标准输出,您不必在像> 这样的输出重定向前显式命名它。相反,您可以简单地输入:
echo This message goes to stderr >&2
由于您似乎担心1>&2 会难以可靠地键入,因此消除多余的1 可能会对您有所鼓励!
【讨论】:
> &2 不起作用,不允许有空格:)
另一种选择
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 的回声”问题(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 "First error line"
echo "Second error line"
echo "Third error line"
} >&2
这仅使用 Bash 内置函数,同时使多行错误输出更不容易出错(因为您不必记住将 &>2 添加到每一行)。
【讨论】:
cat 或任何其他实用程序,这与问题无关。
我的建议:
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 和@987654330 @分别代表stdin、stdout和stderr。
/proc/self 链接在 MacOS 上不起作用,但是,/proc/self/fd/* 在 Android 上的 Termux 上可用,但在 /dev/stderr 上不可用。 How to detect the OS from a Bash script? 可以帮助您确定要使用的变体,从而使您的脚本更具可移植性。
【讨论】:
/proc/self 链接在 MacOS 上不起作用,所以我会坚持使用更直接的 /dev/stderr 方法。此外,正如其他答案/cmets 所述,使用>> 附加可能会更好。
/proc/self/fd/* 在 Android 上的 Termux 上可用,但在 /dev/stderr 上不可用。
echo -n "has '/proc/self/fd/2': " ; [ -e /proc/self/fd/2 ] && echo true || echo false 或使用那个:echo -n "has '/dev/stderr': " ; [ -e /dev/stderr ] && echo true || echo false
不要使用cat,正如这里有些人提到的那样。 cat 是一个程序
而 echo 和 printf 是 bash (shell) 内置函数。启动一个程序 或另一个脚本(上面也提到过)意味着创建一个新进程,并承担所有成本。使用内置函数,编写函数非常便宜,因为不需要创建(执行)进程(-environment)。
开瓶器问“是否有任何标准工具可以将(管道)输出到标准错误”,简短的回答是:不...为什么? ...重定向管道是 unix (Linux...) 和 bash (sh) 等系统中的一个基本概念。
我同意用这样的符号重定向的开场白:&2>1 对于现代程序员来说不是很愉快,但那是 bash。 Bash 并非旨在编写庞大而强大的程序,它旨在帮助管理员以更少的按键完成工作;-)
至少,您可以将重定向放置在行中的任何位置:
$ echo This message >&2 goes to stderr
This message goes to stderr
【讨论】:
cat 的性能权衡与指示某人不要使用 cat 因为它很慢是有区别的。有无数用例表明 cat 是正确的选择,所以这就是我反对您的回答的原因。
echo。即使他使用cat,他也必须使用 bash 重定向。反正。所以,在这里使用cat 绝对没有意义。顺便说一句,我每天使用cat 100 次,但从来没有在开场白要求的上下文中......你明白了吗?
这是一个简单的 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 ...
read 是一个 shell 内置命令,可以打印到 stderr,并且可以像 echo 一样使用而无需执行重定向技巧:
read -t 0.1 -p "This will be sent to stderr"
-t 0.1 是一个超时,它禁用读取的主要功能,将一行标准输入存储到一个变量中。
【讨论】:
James Roth 和Glenn Jackman 建议的组合解决方案
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"
【讨论】:
编写脚本
#!/bin/sh
echo $* 1>&2
这将是你的工具。
如果您不想将脚本放在单独的文件中,也可以创建一个函数。
【讨论】:
这是一个检查最后一个命令的退出状态,显示错误并终止脚本的功能。
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
【讨论】:
Mac OS X:我尝试了接受的答案和其他几个答案,所有这些都导致在我的 Mac 上写入 STDOUT 而不是 STDERR。
这是一种使用 Perl 写入标准错误的可移植方式:
echo WARNING! | perl -ne 'print STDERR'
【讨论】:
stderred着色。