我想区分我的terminal中的STDOUT和STDERR消息。 如果脚本或命令在terminal上打印消息,我想用颜色区分; 可能吗?
(例如stderr字体颜色是红色的,而stdout字体颜色是蓝色的。)
示例(使用粗体):
$date
Wed Jul 27 12:36:50 IST 2011
$datee
bash: datee: command not found
$alias ls
alias ls='ls --color=auto -F'
$aliass ls
bash: aliass: command not found
这是我想到的一个黑客,它似乎工作:
鉴于以下可读性的别名:
alias blue='echo -en "\033[36m"' alias red='echo -en "\033[31m"' alias formatOutput='while read line; do blue; echo $line; red; done'
现在,您需要先将终端中的字体颜色设置为红色(默认情况下,将用于stderr)。 然后,运行你的命令并通过formatOutput
定义的formatOutput
管道输出stdout(它简单地将每行打印为蓝色,然后将字体颜色重置为红色):
shell$ red shell$ ls / somenonexistingfile | formatOutput
上面的命令将在stderr和stdout中打印,您将看到这些行的着色方式不同。
希望这可以帮助
更新:
为了使这个可重用,我把它放在一个小脚本:
$ cat bin/run #!/bin/bash echo -en "\033[31m" ## red eval $* | while read line; do echo -en "\033[36m" ## blue echo $line echo -en "\033[31m" ## red done echo -en "\033[0m" ## reset color
现在你可以用任何命令来使用它:
$ run yourCommand
在bash shell或脚本中创建一个函数:
color()(set -o pipefail;"$@" 2>&1>&3|sed $'s,.*,\e[31m&\e[m,'>&2)3>&1
像这样使用它:
$ color command -program -args
它会以红色显示命令的stderr
。
继续阅读,了解它是如何工作的。 这个命令演示了一些有趣的功能。
color()...
– 创建一个名为color的bash函数。 set -o pipefail
– 这是一个shell选项,用于保留输出到另一个命令中的命令的错误返回码。 这是在由括号创建的子shell中完成的,以便不更改外壳中的pipefail选项。 "$@"
– 执行作为新命令的参数。 "$@"
相当于"$1" "$2" ...
2>&1
– 将命令的stderr
重定向到stdout
以便它成为sed
的stdin
。 >&3
– 1>&3
>&3
简写,这将stdout
重定向到一个新的临时文件描述符3
。 3
后来被路由回stdout
。 sed ...
– 由于上面的重定向, sed
的stdin
是被执行的命令的stderr
。 它的功能是用颜色代码包围每一行。 $'...'
一个bash构造,使它理解反斜线转义的字符 .*
– 匹配整个行。 \e[31m
– 导致以下字符为红色的ANSI转义序列 &
– 扩展为整个匹配字符串的sed
替换字符(本例中为整行)。 \e[m
– 重置颜色的ANSI转义序列。 >&2
– 1>&2
>&2
缩写,将sed
的stdout
重定向到stderr
。 3>&1
– 将临时文件描述符3
重定向到stdout
。 通过将文件描述符链接到一个自定义函数来为颜色添加颜色。 添加到您的.bashrc
以下:
export COLOR_RED="$(tput setaf 1)" export COLOR_RESET="$(tput sgr0)" exec 9>&2 exec 8> >( perl -e '$|=1; while(sysread STDIN,$a,9999) {print "$ENV{COLOR_RED}$a$ENV{COLOR_RESET}"}' ) function undirect(){ exec 2>&9; } function redirect(){ exec 2>&8; } trap "redirect;" DEBUG PROMPT_COMMAND='undirect;'
那么发生了什么? 调试陷阱在执行命令之前和之后立即执行。 因此stderr在执行命令之前被重定向,以启用红色输出。 PROMPT_COMMAND在显示提示之前进行评估,并使用此命令将stderr恢复到正常状态。 这是必要的,因为PS1和PS2 (您的提示)打印在stderr上 ,我不想要红色提示。 瞧,红色输出超过stderr !
你应该检查stderred: https : //github.com/sickill/stderred
是的,这本来是不可能的。 你将不得不破解tty管理(在内核中)。
我在某种程度上完成了一些小的C包装之前,我看到了其他的答案:-)可能是越野车,值是硬编码的,不要使用这个除了测试。
#include "unistd.h" #include "stdio.h" #include <sys/select.h> int main(int argc, char **argv) { char buf[1024]; int pout[2], perr[2]; pipe(pout); pipe(perr); if (fork()!=0) { close(1); close(2); dup2(pout[1],1); dup2(perr[1],2); close(pout[1]); close(perr[1]); execvp(argv[1], argv+1); fprintf(stderr,"exec failed\n"); return 0; } close(pout[1]); close(perr[1]); while (1) { fd_set fds; FD_ZERO(&fds); FD_SET(pout[0], &fds); FD_SET(perr[0], &fds); int max = pout[0] > perr[0] ? pout[0] : perr[0]; int v = select(max+1, &fds, NULL, NULL, NULL); if (FD_ISSET(pout[0], &fds)) { int r; r = read(pout[0], buf, 1024); if (!r) {close(pout[0]); continue;} write(1, "\033[33m", 5); write(1, buf, r); write(1, "\033[0m", 4); } if (FD_ISSET(perr[0], &fds)) { int r; r = read(perr[0], buf, 1024); if (!r) {close(perr[0]); continue;} write(2, "\033[31m", 5); write(2, buf, r); write(2, "\033[0m", 4); } if (v <= 0) break; } return 0; }
编辑:与shell解决方案相比,这个将更经常地保留行/字符的顺序。 (不可能像直接读取tty一样准确。)命中^ C不会显示一个丑陋的错误信息,并且在这个例子中表现正确:
./c_color_script sh -c "while true; do (echo -na; echo -nb 1>&2) done"
我很惊讶,没有人真正知道如何为stdio流着色。 这将为整个(子)shell着色stderr红色:
exec 3>&2 exec 2> >(sed -u 's/^\(.*\)$/'$'\e''[31m\1'$'\e''[m/' >&3)
在这种情况下, &3
将保存原始的stderr流。
你不应该传递任何命令来exec
,只有重定向。 这种特殊情况会导致exec
将当前(子)shell的stdio流替换为接收到的流。
有几个警告:
sed
将在并行子shell中持久运行,因此在写入彩色stdio后立即输出的任何直接输出都可能会击败sed
到tty
。 sed
的部分缓冲:这是如何这些文件类型的功能。 最棘手的问题是第一个,但即使使用默认颜色,也可以通过对所有输出应用类似的处理或多或少地避免竞态条件。
您可以通过使用普通管道运算符( |
)管道到相同的sed
命令,对单个命令执行类似的处理。 管道链是同步执行的,所以没有竞争条件会发生,尽管管道链中的最后一个命令默认收到它自己的子shell。