6

grep 管道输出时如何使 grep 尊重 ANSI 颜色转义?我很高兴使用其他东西(perl?)而不是 grep。

我的用户案例:我想要

 gcc foobar.c | colorgcc | grep regexp
 ls --color | grep filename

可以很好地处理颜色(在使用 ANSI 转义的 unix 终端上)。

我想要的行为测试示例:

echo -e "he\e[35mllo\e[00m" world |grep hell ==> he\e[35mllo\e[00m world 
echo -e "\e[35m removed line\nhello\e[00m" world |grep hell ==> \e[35mhello\e[00m world
echo -e "\e[35m rem\e[1moved line\nhello\e[00m" world | grep hell ==> \e35m\e1mhello\e[00m world

目前第一行给出空字符串,第二行给出未着色的字符串'hello\e[00m world'。这里 \e[35m 和 \e00m 是颜色(属性)修饰符:字母的颜色由形式 \e[P1; 的最后几个颜色(属性)转义序列确定。P2; .. m 其中 P1、P2 等是数字序列;\e[P1m\e[P2m 等价于 \e[P1;P2m 。\e[0m 使颜色默认并忘记所有先前的 \e[..m 序列:\e[34m\e[0m 等价于 \e[0m。有几个独立的属性(粗体、背景颜色、前景/字母颜色);转义序列中的每个数字只影响其中一个。因此 \e[1m\e[35m 等价于 \e[1;35m 但不是 \e[35;1m 也不 \e[35m ; 但是,\e[34m\e[35m 等价于 \e[35m,因为它们都影响相同的属性(即,

4

1 回答 1

2

这是一个非常有趣的问题,这就是我想出的。它很丑陋,但似乎完成了工作:

sed -n '1s/^/\x1b[0m/;H;x;s/\n//;p;s/.*\(\x1b\[[0-9]*m\(;[0-9]*m\)*\).*/\1/;h' |
  grep `sed 's/./\0\\\\(\x1b\\\\[[0-9]*m\\\\(;[0-9]*m\\\\)*\\\\)*/g' <<< hell`

您正在搜索的术语将放在最后(代替“地狱”),以下是您提供的文本的一些示例(使用 hexdump 显示颜色):

$ echo -e "he\e[35mllo\e[00m" world |
> sed -n '1s/^/\x1b[0m/;H;x;s/\n//;p;s/.*\(\x1b\[[0-9]*m\(;[0-9]*m\)*\).*/\1/;h' |
> grep `sed 's/./\0\\\\(\x1b\\\\[[0-9]*m\\\\(;[0-9]*m\\\\)*\\\\)*/g' <<< hell` |
> hexdump -C
00000000  1b 5b 30 6d 68 65 1b 5b  33 35 6d 6c 6c 6f 1b 5b  |.[0mhe.[35mllo.[|
00000010  30 30 6d 20 77 6f 72 6c  64 0a                    |00m world.|
0000001a

$ echo -e "\e[35m removed line\nhello\e[00m" world |
> sed -n '1s/^/\x1b[0m/;H;x;s/\n//;p;s/.*\(\x1b\[[0-9]*m\(;[0-9]*m\)*\).*/\1/;h' |
> grep `sed 's/./\0\\\\(\x1b\\\\[[0-9]*m\\\\(;[0-9]*m\\\\)*\\\\)*/g' <<< hell` |
> hexdump -C
00000000  1b 5b 33 35 6d 68 65 6c  6c 6f 1b 5b 30 30 6d 20  |.[35mhello.[00m |
00000010  77 6f 72 6c 64 0a                                 |world.|
00000016

第一个 sed 命令将当前颜色设置添加到每行的开头,这对于第二个示例是必要的,其中颜色设置在 grep 将跳过的行上。作为 grep 参数的 sed 命令插入一个正则表达式,该正则表达式将匹配搜索词中每个字符之间的任意数量的颜色转义。

这是 egrep 版本:

sed -n '1s/^/\x1b[0m/;H;x;s/\n//;p;s/.*\(\x1b\[[0-9]*m\(;[0-9]*m\)*\).*/\1/;h' |
  egrep `sed 's/./\0(\x1b\\\\[[0-9]*m(;[0-9]*m)*)*/g' <<< hell`
于 2013-02-06T22:50:02.040 回答