彩色 grep 输出:不是 GREP_OPTIONS 不是别名

彩色 grep 输出:不是 GREP_OPTIONS 不是别名

我想要 的彩色输出grep

.... 但

  • 策略 1:GREP_OPTIONS。但这已被弃用。看http://www.gnu.org/software/grep/manual/html_node/Environment-Variables.html
  • 策略 2:乍一看,GREP_COLORS 看起来像是一个解决方案,但它的作用有所不同。
  • 策略三:别名。这不适用于find ... | xargs grep,因为 xargs 不评估别名。
  • 策略 4:编写一个简单的包装脚本。不,我认为这太肮脏了,带来的麻烦比解决的问题还要多。
  • 策略5:修补源代码
  • 策略6:联系grep开发人员,要求更换GREP_OPTIONS
  • 策略 NICE-and-EASY:...缺少此内容。我没有任何线索。

如何解决这个问题?

答案1

OP 所说的一些原因并没有事实依据(即缺乏对 shell 脚本如何工作的理解以及缺乏对简单包装脚本如何不影响性能的理解)。

在这个答案中,我证明策略 4 实际上是一个很好的解决方案,原因有很多(易于实现、开销低、对所有用例都灵活等):

在大多数发行版上,grep安装在/bin(典型)或/usr/bin(OpenSUSE,也许其他)中,默认PATH包含/usr/local/binbefore/bin/usr/bin.这意味着如果您/usr/local/bin/grep使用

#!/bin/sh
exec /bin/grep --color=auto "$@"

其中/bin/sh是您的发行版提供的 POSIX 兼容 shell,通常是 bash 或 dash。如果grep在 中/usr/bin,则将其设为

#!/bin/sh
exec /usr/bin/grep --color=auto "$@"

包装脚本的性能开销很小

该脚本的开销很小。该exec语句的意思是脚本解释器被二进制替换grep;这意味着 shellgrep在执行时不会保留在内存中。因此,唯一的开销是脚本解释器的一次额外执行,即挂钟时间的一小部分延迟。延迟大致恒定(仅根据 和 是否grepsh在页面缓存中,以及可用的 I/O 带宽多少而变化),并且不取决于grep执行多长时间或处理多少数据。

那么,延迟有多长,即包装脚本增加的开销?

要找出答案,请创建上述脚本并运行

time /bin/grep --version
time /usr/local/bin/grep --version

在我的机器上,前者实时需要 0.005 秒(经过大量运行),而后者实时需要 0.006 秒。因此,在我的机器上使用包装器的开销是每次调用 0.001 秒(或更少)。

这是微不足道的。

我也没有看到任何“肮脏”的东西,因为许多常见的应用程序和实用程序都使用相同的方法。要在/bin和中查看计算机上此类的列表/usr/bin,只需运行

file /bin/* /usr/bin/* | sed -ne 's/:.*shell script.*$//p'

在我的机器上,上面的输出包括我经常使用的egrepfgrepzgrepwhich7zchromium-browserldd和。xfig除非您认为整个发行版因依赖包装器脚本而“肮脏”,否则您没有理由认为此类包装器脚本“肮脏”。

将包装脚本放在您的 PATH 上可能出现的问题

如果只有人类用户(而不是脚本)使用默认支持颜色的 grep 版本(如果输出到终端),则可以命名包装器脚本colorgrepcgrepOP 认为合适的任何名称。

这避免了所有可能的兼容性问题,因为 的行为grep根本不会改变。


使用包装器脚本启用grep选项,但要避免任何新问题:

我们可以轻松地重写包装器脚本以支持自定义,GREP_OPTS即使GREP_OPTIONS不支持(因为它已被弃用)。这样,用户可以简单地添加export "GREP_OPTIONS=--color=auto"或类似于他们的个人资料。/usr/local/bin/grep那么就是

#!/bin/sh
exec /bin/grep $GREP_OPTIONS "$@"

请注意, 周围没有引号$GREP_OPTIONS,以便用户可以指定多个选项。

在我的系统上,time /usr/local/bin/grep --version使用GREP_OPTIONSempty或使用GREP_OPTIONS=--color=auto,执行与包装器脚本的先前版本一样快;即,通常比普通的执行时间要长一毫秒grep

最后一个版本是我个人推荐使用的版本。

综上所述,OP的策略4:

  • grep开发商推荐的

  • 实现起来很简单(两行)

  • 开销微不足道(在这台特定笔记本电脑上每次调用会增加一毫秒的延迟;在每台机器上都可以轻松验证)

  • 可以作为添加支持的包装脚本来实现GREP_OPTS(以替换 deprecated/unsupported GREP_OPTIONS

  • 可以实现(如colorgrep/ cgrep),根本不影响脚本或现有用户

因为它是一种已经在 Linux 发行版中广泛使用的技术,所以它是一种常见技术,而不是“脏”技术。

如果作为单独的包装器 ( colorgrep/ ) 实现,它不会产生新问题,因为它根本cgrep不影响行为。grep如果作为添加支持的包装脚本实现GREP_OPTS,则使用GREP_OPTS=--color=auto与上游添加默认值具有完全相同的风险(现有脚本的问题)--color=auto。因此,“产生的问题多于解决的问题”的评论是完全错误的:不会产生额外的问题。

答案2

您提供的第一个策略的文档显示:

请改用别名或脚本。例如,如果 grep 位于目录“/usr/bin”中,您可以将 $HOME/bin 添加到您的 PATH 中,并创建一个包含以下内容的可执行脚本 $HOME/bin/grep:

#! /bin/sh
export PATH=/usr/bin
exec grep --color=auto --devices=skip "$@"

因此,如果别名对您来说不可能,则包装脚本是唯一的方法。

答案3

该变量被弃用的原因GREP_OPTIONS是,当在脚本中的某个位置调用它时,它往往会导致问题,grep并且该脚本无法使用来自该变量的替代选项。如果你编写一个包装脚本,grep那么你也会遇到同样的问题,除非你给它起一个不同的名字

$ cat ~/bin/cgrep
#!/bin/sh
exec grep --color=always "$@"
$ find … -exec cgrep … {} +

或者,将您最喜欢的选项存储在变量中。在 zsh 以外的 shell 中,如果选项包含通配符 ( \[*?),这会很麻烦,但否则您可以仅使用不带引号的变量来获取带参数的命令。

cgrep=(grep --color=always)
find … -exec $cgrep … {} +

请注意,GNU 和 BSD grep 可以递归地处理目录树,这在大多数情况find下减轻了组合的需要。grep

答案4

最简单的方法是使用别名(策略 3)。如果您确实关心该xargs命令,您仍然可以使用 bash 函数覆盖它。

alias grep='grep --color'
xargs() {
    local args
    for ((i=1; i<=$#; i++))
    do
            if [[ "-E -L -P -I -s -d" == *"${!i}"* ]]; then
                    ((i=i+1))
            elif [[ ${!i:0:1} != "-" ]]; then
                    if [[ ${!i} == "grep" ]]; then
                            args="--color"
                    fi
                    /usr/bin/xargs ${@:1:i} $args ${@:i+1}
                    return;
            fi
    done
}

但这并不比使用包装命令更好,这似乎是团队推荐的解决方案grep

/usr/local/bin/grep:

#!/bin/bash
/bin/grep --color "$@"

以我的拙见,您应该联系grep开发团队,要求他们提供一个简单的变量替换,以便根据某些环境变量GREP_OPTIONS启用颜色。grep

color对于他们来说,默认启用该选项或在GREP_COLORS设置后启用该选项将非常简单。

相关内容