有没有办法让bash以红色显示stderr消息?

评论

我猜bash永远不会使输出变色:某些程序可能想解析某些内容,而变色会破坏转义序列的数据。我想一个GUI应用程序应该处理颜色。

将BalázsPozsár和killdash9的答案结合在一起即可得出清晰的结果:函数颜色{“ $ @” 2>>(sed $'s .. *,\ e [31m&\ e [m,')}}适用于bash和zsh。无法将此作为答案B / C信誉。

我正在等待修改bash的答案。以下所有解决方案实际上都会修改stderr,甚至可能重新排序stderr。当必须保留stderr的确切字节序列时,stdout会中断事情,例如配管时。

这些解决方案的缺点是它们逐行工作,即它们缓冲输入直到遇到NL。尽管在大多数情况下这可能还可以,但是它会禁用依赖于CR和输出刷新的各种进度条。

#1 楼

command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)


评论


大!但是我想知道是否有一种方法可以使其永久:)

–kolypto
09年8月26日在21:47

大提示!建议:在;之前添加>&2。完成),则实际上将用于stderr的输出写入stderr。如果要捕获程序的正常输出,这将很有帮助。

– henko
2012年10月31日上午8:12

以下使用tput,在我看来,它更具可读性:命令2>>(在读取行时;执行echo -e“ $(tput setaf 1)$ line $(tput sgr0)”>&2;完成)

– Stefan Lasiewski
13年2月14日在21:59

我认为为每条输出线执行2个输出处理根本不是一件好事。也许您可以将tput命令的输出存储在变量中,并将其用于每个回显。但是话又说回来,可读性并不是真的更好。

– BalazsPozsár
2014年10月7日12:09

此解决方案不保留空格,但为简洁起见,我喜欢它。 IFS =读-r行应该有帮助,但没有帮助。不知道为什么。

–马克斯·墨菲(Max Murphy)
16年7月1日在11:05

#2 楼

方法1:使用进程替换:

command 2> >(sed $'s,.*,\e[31m&\e[m,'>&2)


方法2:在bash脚本中创建函数:

color()(set -o pipefail;"$@" 2>&1>&3|sed $'s,.*,\e[31m&\e[m,'>&2)3>&1


像这样使用它:

$ color command


这两种方法都会以红色显示命令的stderr

继续阅读以了解方法2的工作原理。此命令演示了一些有趣的功能。



color()... —创建一个名为color的bash函数。

set -o pipefail —这是一个shell选项保留命令的错误返回代码,该命令的输出通过管道传递到另一个命令。这是在由括号创建的子外壳中完成的,以免更改外壳中的pipefail选项。

"$@" —将函数的参数作为新命令执行。 "$@"等效于"" "" ...


2>&1 —将命令的stderr重定向到stdout,使其成为sedstdin

>&31>&3的简写,这会将stdout重定向到新的临时文件描述符33稍后被路由回stdout

sed ... —由于上述重定向,sedstdin是已执行命令的stderr。它的功能是用颜色代码包围每行。

$'...'一个bash构造,使它可以理解反斜杠转义的字符

.* —匹配整行。

\e[31m-导致以下字符变为红色的ANSI转义序列

&-sed替换字符,扩展为整个匹配的字符串(在这种情况下为整行)。 br />
\e[m-重置颜色的ANSI转义序列。

>&2-1>&2的缩写,它将sedstdout重定向到stderr

3>&1 —将临时文件描述符3重定向回stdout


评论


+1个最佳答案!绝对低估了!

– muhqu
2013年9月20日上午11:27

很好的答案,甚至更好的解释

–Daniel Serodio
2014年10月22日19:56

有没有办法使其在zsh中工作?

–艾尔·莱文(Eyal Levin)
16年8月25日在9:14

ZSH无法识别速记重定向表格。它只需要再加上两个1,即:zsh:color()(set -o pipefail;“ $ @” 2>&1 1>&3 | sed $'s。*,\ e [31m&\ e [m,'1 >&2)3>&1

–雷金
18年8月2日在10:12

这不会保留执行顺序。

–乔纳
20-4-11的13:55

#3 楼

您还可以签出stderred:https://github.com/sickill/stderred

评论


哇,这个实用程序很棒,它唯一需要做的就是拥有一个apt存储库,只需一行即可为所有用户安装它,而无需做更多的工作来启用它。

–索林
2012年4月3日在14:17

当我在单独的终端中使用构建脚本对其进行测试时,似乎运行良好,但是我犹豫要在全球范围内使用它(在.bashrc中)。不过谢谢!

–乔尔·普拉(Joel Purra)
2012年8月24日15:18

在OS X El Capitan中,此工作方式(DYLD_INSERT_LIBRARIES)在系统二进制文件中被“破坏”,因为它们受到SIP的保护。因此,最好使用其他答案中给出的bash选项。

–hmijail哀悼辞职者
16-4-22在21:41

对于MacOS的@hmijail,请关注github.com/sickill/stderred/issues/60,以便我们可以找到一种解决方法,虽然部分解决方法已经存在,但存在一些问题。

–索林
18年7月16日在7:57

这真的很巧妙。这是我所见的唯一答案,不会扰乱stdout和stderr的顺序(据我所知,所有基于shell的解决方案都可以这样做)。

–唐·哈奇
19/12/25在5:29

#4 楼

使stderr永久变为红色的重击方法是使用“ exec”重定向流。将以下内容添加到您的bashrc中:

exec 9>&2
exec 8> >(
    while IFS='' read -r line || [ -n "$line" ]; do
       echo -e "3[31m${line}3[0m"
    done
)
function undirect(){ exec 2>&9; }
function redirect(){ exec 2>&8; }
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'


我之前在此上发布过:如何为STDOUT和STDERR设置字体颜色

评论


相关:unix.stackexchange.com/questions/367636/…

– phil294
17年5月29日在3:59

到目前为止,这是最好的答案。易于实现,无需安装/不需要sudo特权,并且可以推广到所有命令。

–戴维斯(Luke Davis)
17年9月26日在2:25

不幸的是,这在命令链接(命令&& nextCommand || errorHandlerCommand)中不能很好地发挥作用。错误输出在errorHandlerCommand输出之后。

–carlin.scott
18年6月18日在23:30

类似地,如果我以此来两次获取〜/ .bashrc,我的终端基本上会锁定。

–多尔夫
'18 Sep 11'在20:11

@Dolf:在我的bashrc中,我很容易用周围的if语句来防止这种情况发生,以防止重新加载此代码。否则,问题是重定向已经执行之后,重定向了'exec 9>&2'。如果您知道> 2最初指向的位置,则可以将其更改为常数。

–目标
'18 -10-1在8:48

#5 楼

http://sourceforge.net/projects/hilite/

#6 楼

我制作了一个包装脚本,以纯bash形式实现了BalázsPozsár的答案。
将其保存在$ PATH和前缀命令中以使其输出着色。


    #!/bin/bash

    if [  == "--help" ] ; then
        echo "Executes a command and colorizes all errors occured"
        echo "Example: `basename q4312078q` wget ..."
        echo "(c) o_O Tync, ICQ# 1227-700, Enjoy!"
        exit 0
        fi

    # Temp file to catch all errors
    TMP_ERRS=$(mktemp)

    # Execute command
    "$@" 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" | tee --append $TMP_ERRS; done)
    EXIT_CODE=$?

    # Display all errors again
    if [ -s "$TMP_ERRS" ] ; then
        echo -e "\n\n\n\e[01;31m === ERRORS === \e[0m"
        cat $TMP_ERRS
        fi
    rm -f $TMP_ERRS

    # Finish
    exit $EXIT_CODE



评论


如果将“ | tee ...”放在“完成”之后,可以提高效率。

–朱利亚诺
09年8月27日在1:27

#7 楼

您可以使用类似这样的函数


 #!/bin/sh

color() {
      printf '3[%sm%s3[m\n' "$@"
      # usage color "31;5" "string"
      # 0 default
      # 5 blink, 1 strong, 4 underlined
      # fg: 31 red,  32 green, 33 yellow, 34 blue, 35 purple, 36 cyan, 37 white
      # bg: 40 black, 41 red, 44 blue, 45 purple
      }
string="Hello world!"
color '31;1' "$string" >&2




我附加>&2以打印到stderr

评论


无法解决问题。您尚未提供将stderr与stdout分开的方法,这是O.P.感兴趣的。

– Jeremy Visser
09年8月27日在1:54

#8 楼

我有一个O_o Tync脚本的稍微修改的版本。我需要为OS X Lion制作这些mod,但这并不完美,因为脚本有时会在包装命令之前完成。我增加了睡眠,但是我敢肯定有更好的方法。

#!/bin/bash

   if [  == "--help" ] ; then
       echo "Executes a command and colorizes all errors occured"
       echo "Example: `basename q4312078q` wget ..."
       echo "(c) o_O Tync, ICQ# 1227-700, Enjoy!"
       exit 0
       fi

   # Temp file to catch all errors
   TMP_ERRS=`mktemp /tmp/temperr.XXXXXX` || exit 1

   # Execute command
   "$@" 2> >(while read line; do echo -e "$(tput setaf 1)$line\n" | tee -a $TMP_ERRS; done)
   EXIT_CODE=$?

   sleep 1
   # Display all errors again
   if [ -s "$TMP_ERRS" ] ; then
       echo -e "\n\n\n$(tput setaf 1) === ERRORS === "
       cat $TMP_ERRS
   else
       echo "No errors collected in $TMP_ERRS"
   fi
   rm -f $TMP_ERRS

   # Finish
   exit $EXIT_CODE


#9 楼

此解决方案为我工作:https://superuser.com/questions/28869/immediately-tell-which-output-was-sent-to-stderr

我已将此功能放入我的.bashrc.zshrc

# Red STDERR
# rse <command string>
function rse()
{
    # We need to wrap each phrase of the command in quotes to preserve arguments that contain whitespace
    # Execute the command, swap STDOUT and STDERR, colour STDOUT, swap back
    ((eval $(for phrase in "$@"; do echo -n "'$phrase' "; done)) 3>&1 1>&2 2>&3 | sed -e "s/^\(.*\)$/$(echo -en \033)[31;1m$(echo -en \033)[0m/") 3>&1 1>&2 2>&3
}


然后例如:

$ rse cat non_existing_file.txt


会给我红色输出。

评论


您可以添加set -o pipefail;之前(用于重定向退出代码的eval

–kvaps
19年6月27日在14:34

还在eval上添加“以保留参数中的空格

–kvaps
19年6月27日在14:42

#10 楼

使用xargs和printf:

command 2> >(xargs -0 printf "\e[31m%s\e[m" >&2)


#11 楼

使用fifos的版本

mkfifo errs
stdbuf -o0 -e0 -i0 grep . foo | while read line; do echo -e "\e[01;31m$line  \e[0m" >&2; done &
stdbuf -o0 -e0 -i0 sh $script 2>errs