是否有一个标准的bash工具像echo一样工作,但输出到stderr而不是stdout?
我知道我可以做echo foo 1>&2,但它有点难看,而且,我怀疑,容易出错(例如,当事情发生变化时,更容易被编辑错)。
- 相关:stackoverflow.com/a/12704488/194894
- 为什么不,echo"foo"> /dev/stderr?或者是echo"foo">&2?我想也是一样。
- 为什么不做echo"foo"> /dev/tty?有趣的是,你怎么就不能把它寄给/dev/null…P
这个问题很古老,但你可以这样做,这有助于阅读:
操作符>&2的字面意思是将文件描述符1(stdout的地址重定向到该命令1的文件描述符2(stderr的地址。根据您对它的理解程度,请阅读以下内容:http://wiki.bash-hacker.org/how to/redirection_tutorial
要避免与其他重定向交互,请使用子外壳
1>&2将文件描述符2复制到文件描述符1。因此,在执行此重定向之后,两个文件描述符都将引用同一个文件:一个文件描述符2最初是引用到的。
- alias errcho='>&2 echo'
- 我很早以前就学会了这个把戏。这个页面有一些很好的信息。tldp.org/ldp/abs/html/io-redirection.html文件
- @allonhadaya,运算符">&;2"字面意思是将文件描述符1(stdout)的地址重定向到该命令的文件描述符2(stderr)的地址。根据您对它的理解程度,请阅读以下内容:wiki.bash-hacker.org/how to/redirection_教程
- @BCS除了alias不适用于bash脚本之外。
- @Becko,你得去shopt -s expand_aliases那里。
- @我不知道如何在shell脚本中使用alias。使用errcho(){ >&2 echo $@; }可能更安全。
- >&;2通常放在末尾。这是可行的,但使用频率较低
- 在我使用类似Unix的系统将近40年的时间里,我从来没有想过你可以将重定向放在任何地方,但最后却放在了尽头。把它放在前面会让它更明显(或者像@marcoaurelio所说的"方便阅读")。+教我一些新东西。
- 谢谢,学到了新东西
- 我附和了@hephaestus的评论,开始将重定向放在更靠近行的开始处,以提高可见性。认识到以后的重定向会覆盖这一点。另一个程序员可能会对这一行进行更改:>&2 echo"Go to stderr"这样,而不理解事情是如何工作的:>&2 echo"Go to stderr">xx"But now, it goes to file xx"。
- @BCS在将它与其他重定向结合后,将提供长时间的调试娱乐。
- @Bradenbest要学究(但这很重要),你应该使用一个函数(和你一样)并引用$@such:echoerr()>&2 echo"$@";如果不是,愚蠢的东西,如"echoerr hello"2>&1"world"会无意中取消引用"2>&1"。
- @约翰纳尔苏普不会引用美元,因为它被解释为一个论点,打破了像errecho -n this error should print without a newline这样的东西?
- @Bradenbest"$@"由bash特别处理。它将扩展所有单独引用它们的参数。
- @Hephaestus注意,这只适用于echo,因为它使用的是文件描述符0、1和2使用的默认伪终端。查看"重定向顺序"部分:wiki.bash-hacker.org/howto/redirection_教程
- @马可奥雷里奥,你能不能扩大一个子外壳的理由/需求?可能是模棱两可或有风险的例子
- @bobdoolitt>&;2将应用程序stdout重定向到用户界面/系统stderr输出,而不是同时发送到两者。你能详细说明一下你在看什么吗?在常规shell会话中,除非另有指定,否则bot stderr和stdout将打印到屏幕上。
- 当然可以。我不知道我在想什么。我将删除我的评论以避免混淆。谢谢。
您可以定义一个函数:
1 2
| echoerr() { echo"$@" 1>&2; }
echoerr hello world |
这将比脚本快,并且没有依赖关系。
Camilo Martin的bash特定建议使用"here字符串",并将打印您传递给它的任何内容,包括echo通常会接受的参数(-n):
1
| echoerr() { cat <<<"$@" 1>&2; } |
格伦·杰克曼的解决方案也避免了吞咽论点的问题:
1 2
| echoerr() { printf"%s
""$*">&2; } |
- 我得说Echo有点不可靠。echoerr -ne xt不打印"-ne xt"。最好用printf来解决这个问题。
- 哦,你也可以用猫:echoerr() { cat <<<"$@" 1>&2; }。
- 我不知道。补充。
- 如果你想让任何子程序获取函数,就执行一个export -f echoerr。
- 或者,printf"%s
""$*">&2。
- @camilomartin cat <<<"$@"甚至更糟;它将参数之间的所有空格压缩为一个,因此为了可靠性,您必须引用传递给它的内容。
- @gkfx不,它没有,echoerr 'foo ? bar'在foo和bar之间有两个空格。(我必须添加一个零宽度的连接符,以使它在此注释中显示两个空格,因此不要复制和粘贴它,否则控制台中将显示三个空格)。
- @camilomartin将双空格放在引号中(或转义它等)可以正常工作,但是这个答案中的第一个代码块没有引号。我是说echoerr a ? b。不过,我刚刚检查过,实际的echo命令的行为与您的命令相同,所以很明显这不是bug。
- @GKFX当然只有在报价时才能正常工作。为什么人们不引用他们的字符串是我无法理解的。(如果不引用,所有由一个或多个$IFS空格分隔的内容都作为单独的论点发送,在echo的情况下,这意味着将它们与0x20连接起来,但不引用的危险远远大于2个更少字符键入的便利性)。
- @卡米洛马丁,我现在明白了;我已经习惯了这张未经引用的表格,因为我看得太多了,从来没有意识到其中的陷阱。
- @GKFX这是一个常见的错误(不幸的是)。在这方面,当您不想解释任何内容时,请记住使用单引号(不仅仅是$variables,还要考虑echo"why!?"与echo 'why!?',还要注意echo '\'是如何正确的)。bash很漂亮,一旦你记住了这些东西,但它被对它的特性和它们引起的错误的误解所阻碍(同样的事情发生在javascript上,它有很长的路要走,但仍然被那些被第一印象困扰的人所回避)。
- 删除不安全的答案($@)是有意义的,只删除最后两个正确的答案。
由于1是标准输出,因此您不必在像>这样的输出重定向前显式地命名它,而是只需键入:
1
| echo This message goes to stderr >&2 |
由于您似乎担心1>&2对您来说很难可靠地输入,消除多余的1可能会对您有轻微的鼓励!
- 我更多的是想在某些复制粘贴失败的情况下丢失或从后缀中分离。
- 使用echo >&2 some message或echo >&2"some message"形式对您来说是更好的选择吗?
- 有时我会使用第二种形式,以防以后编辑文本并向some message添加标点符号,如果没有引号保护,则这些标点符号对shell来说是特殊的。引号还使我的编辑器语法将some message突出显示为数据而不是命令,这在解析shell脚本时很有视觉帮助。
- 比起公认的答案,我更喜欢这个解决方案。
另一选择
- 此选项是否可移植?有人知道这是否适用于某些Unix风格?
- 它在某些特定的chroots中不起作用,这些chroots无法访问/dev/stderr。
- 如果执行此行的脚本(我们称之为foo)有自己的stderr重定向(例如foo >foo.log 2>&1),那么echo foo >/dev/stderr将删除前面的所有输出。用>>代替:echo foo >>/dev/stderr。
- 同样,您也有/dev/fd/2。
- 这是我最喜欢的。可读性更高。
- @这当然是便携式的:/proc/self/fd/2。请看下面我的答案:)
不,这是标准的方法。它不应该导致错误。
- 它不应该导致错误,但我可能更容易出错。哦,没什么大不了的。
- 唯一失败的方法是,如果stdout的文件ID不是1,或者stderr的文件ID不是2。因为这些常量是由posix.1定义的,我认为这是bash构建的先决条件,所以这对于可预见的未来是有效的。因此,我很好奇你所说的"当事情发生变化时,很可能被编辑错"是什么意思。你对人们把"echo"这个词改成其他词也有类似的问题吗?
- @Mike Desimone:如果其他人弄乱了代码,在输出中乱转,而且实际上不知道bash,那么他们很容易删除(或错误输入)1>&2。我们都希望这不会发生,但我相信我们都去过这样的地方。
- ( echo something 1>&2 ; something else ) > log->(echo something; cp some junk 1>&2 ; something else) > logoops.
- imho,如果有人弄乱了代码,不知道bash,这可能是你的问题中最小的一个。
- 我认为如果这可能是一个问题,你应该开始使用一种不同的语言:试图使bash变得简单是愚蠢的冒险。
这是一个简单的stderr函数,它将管道输入重定向到stderr。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #!/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 |
- 我想你可以用Alias做同样的事情,而且要紧凑得多
如果您不介意将消息也记录到syslog中,不那么难看的方法是:
-s选项意味着:"将消息输出到标准错误和系统日志。"
不要像这里提到的那样使用cat。cat是一个程序而echo和printf是bash(shell)内置的。启动一个程序或其他脚本(也如上所述)意味着用所有的成本创建一个新的过程。使用内置的,编写函数是相当便宜的,因为不需要创建(执行)一个进程(环境)。
opner询问"是否有任何标准工具输出(管道)到stderr",schort回答是:否…为什么?…在Unix(Linux…)和Bash(SH)等系统中,预测管道是建立在这些概念基础上的一个基本概念。
我同意开场白的观点,即用这样的符号重定向:&2>1对现代程序员来说不是很愉快,但这就是bash。bash不打算编写庞大而健壮的程序,它的目的是帮助管理员使用更少的按键进行工作;-)
至少,您可以将重定向放在行中的任何位置:
1 2
| $ echo This message >&2 goes to stderr
This message goes to stderr |
- 告诉开发人员不要仅仅因为性能原因而使用程序是过早的优化。优雅、易于遵循的方法应该优先于难以理解、性能更好的代码(以毫秒为顺序)。
- @古ypaddock对不起,你没有正确读完。它是关于重新定向管道的,这是由bash很好地处理的。如果不喜欢bash重定向的(丑陋的)语法,他应该停止实现bash脚本或学习bash方法。其次,您应该知道与yust调用bash builtin相比,启动一个新的Prozes有多贵。
- 让某人知道bash内置与cat的性能权衡,并指示某人不要使用cat,因为它很慢,这两者之间存在差异。在无数的用例中,cat是正确的选择,所以我反对你的答案。
- @开瓶器要求更换一个echo。即使他使用cat,他也必须使用bash重定向。不管怎样。因此,在这里使用cat毫无意义。顺便说一句,我一天用100次cat100次,但从未在开场白要求的情况下…你明白了吗?
注意:我回答的是帖子-不是误导性/模糊的"输出到stderr的回音"问题(已经被op回答)。
使用一个函数来显示意图和源代码您想要的实现。例如。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #!/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为:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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"; } |
操作中处理问题的原因:
- 最好的语法(有意义的词而不是难看的符号)
- 很难出错(尤其是如果重用脚本)
- 它不是标准的bash工具,但它可以是您或您的公司/组织的标准shell库。
其他原因:
- 清晰-向其他维护人员显示意图
- 速度-函数比shell脚本快
- 可重用性-一个函数可以调用另一个函数
- 可配置性-无需编辑原始脚本
- 调试-更容易找到导致错误的线路(特别是当你正在处理大量的重定向/过滤输出时)
- 健壮性-如果函数丢失,并且无法编辑脚本,则可以使用具有相同名称的外部工具(例如,日志错误可以别名为Linux上的记录器)。
- 切换实现-您可以通过删除库的"x"属性切换到外部工具。
- 输出不可知-您不再需要关心它是否会进入stderr或其他地方。
- 个性化-您可以使用环境变量配置行为
这个问题已经得到了答复,而且得到了很多选票。只是为了记录:
echo"my errz"> /proc/self/fd/2
将有效输出到stderr。说明:/proc/self是当前进程的链接,/proc/self/fd保存进程打开的文件描述符。那么,0、1和2分别代表stdin、stdout和stderr。
我发现它更可读。而且,这可能适用于大多数Linux发行版:
echo"my errz"> /dev/stderr
使其更易于阅读。
- /proc/self链接在MacOS上不起作用,所以我将坚持更直接的/dev/stderr方法。另外,如其他回答/评论中所述,最好使用>>附加。
- android上的termux上提供/proc/self/fd/*,但不提供/dev/stderr。
read是一个shell内置命令,打印到stderr,可以像echo一样使用,而不执行重定向技巧:
1
| read -t 0.1 -p"This will be sent to stderr" |
-t 0.1是一个超时,它禁用read的主要功能,将一行stdin存储到变量中。
我最近偶然发现的另一个选择是:
1 2 3 4 5
| {
echo"First error line"
echo"Second error line"
echo"Third error line"
} >&2 |
这只使用了bash内置模块,同时减少了多行错误输出的错误倾向(因为您不必记住向每行添加&>2)。
- 不敢相信,当我推荐使用bash重定向时,你投了我反对票,在你自己的回答中,你使用的是bash重定向。
制作剧本
那就是你的工具。
或者,如果不想在单独的文件中有一个脚本,就创建一个函数。
- 最好是作为一个函数(如詹姆斯·罗斯的答案),最好是传递所有的论点,而不仅仅是第一个。
- 为什么函数更好?(或者,也可以说:"最好解释一下为什么会更好……"
- @函数更好的一个原因是,当调用脚本时,通常会创建一个新的shell实例,以提供执行脚本的环境。另一方面,函数被放置到当前运行的shell环境中。在这种情况下,调用一个函数将是一个更有效的操作,因为可以避免创建shell的另一个实例。
MacOSX:我尝试了被接受的答案和其他一些答案,所有这些都导致在我的Mac上写stdout而不是stderr。
下面是一种使用Perl编写标准错误的可移植方法:
1
| echo WARNING! | perl -ne 'print STDERR' |
- lol downvote所有你想要的,但这是我在代码中实际使用的解决方案!