11

I want colored output of grep.

.... But

  • Strategy 1: GREP_OPTIONS. But this is deprecated. See http://www.gnu.org/software/grep/manual/html_node/Environment-Variables.html
  • Stragegy 2: GREP_COLORS look like a solution at the first sight, but this does something different.
  • Strategy 3: alias. This does not work for find ... | xargs grep, since xargs does not evaluate aliases.
  • Strategy 4: Write a simple wrapper script. No, I think this is too dirty and makes more trouble than it solves.
  • Strategy 5: patch the source code
  • Strategy 6: Contact grep developers, ask for a replacement of GREP_OPTIONS
  • Strategy NICE-and-EASY: ... this is missing. I have no clue.

How to solve this?

5
  • 1
    You have rejected two suggestions to use a wrapper script (your Strategy 4) as "not really an answer". Can you describe what is "dirty", "troublesome", or "not really an answer" about it? Maybe that's a separate problem that can be worked around. – JigglyNaga Mar 16 '17 at 15:06
  • 2
    strategy 5 is patch the source code and set color_option to 2... – don_crissti Mar 16 '17 at 15:07
  • 2
    @JigglyNaga here is my explanation why a wrapper script is not a solution. Our team manages several servers. Less then thousand at the moment, but the count is increasing. Yes, we use configuration management and it would be easy to deploy a script to all of them. But I want things to be easy and straightforward (think of new members in the team. I don't want to confuse them). The --color option already has the value auto. I just don't know why you can't activate it by default. – guettli Mar 18 '17 at 5:52
  • You should use strategy 4 or 5 -- I'd prefer strategy 4 with a minimal dash/sh script (exec grep --color=auto "$@"), optionally with a different name (grepc or colorgrep). This has neglible overhead (and no extra concurrent processes at runtime). The reason you have labeled them "not easy enough" is the fact that you do not see this feature useful enough to spend the (relatively little) one-time effort to implement it, and are seeking for someone else to do it for you. Because of this, your "not really an answer" comments to the posted answers are quite rude. – Nominal Animal Mar 19 '17 at 20:20
  • 1
    @NominalAnimal Yes, you are right "not really an answer" sounds rude. I am not a native speaker. Which wording (transferring the same message) would be better? – guettli Mar 20 '17 at 9:30
13
+25

Some of the reasons OP has stated the options are unsuitable have no basis in reality. Here, I show what kind of effects using OP's strategy 4 has:


On most distributions, grep is installed in /bin (typical) or /usr/bin (OpenSUSE, maybe others), and default PATH contains /usr/local/bin before /bin or /usr/bin. This means that if you create /usr/local/bin/grep with

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

where /bin/sh is a POSIX-compatible shell provided by your distribution, usually bash or dash. If grep is in /usr/bin, then make that

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

The overhead of this script is minimal. The exec statement means that the script interpreter is replaced by the grep binary; this means that the shell does not remain in memory while grep is being executed. Thus, the only overhead is one extra execution of the script interpreter, i.e. a small latency in wall clock time. The latency is roughly constant (varies only depending on whether grep and sh are already in page cache or not, and on how much I/O bandwidth is available), and does not depend on how long grep executes or how much data it processes.

So, how long is that latency, i.e. the overhead added by the wrapper script?

To find out, create the above script, and run

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

On my machine, the former takes 0.005s real time (across a large number of runs), whereas the latter takes 0.006s real time. Thus, the overhead of using the wrapper on my machine is 0.001s (or less) per invocation.

This is insignificant.

I also fail to see anything "dirty" about this, because many common applications and utilities use the same approach. To see the list of such on your machine in /bin and /usr/bin, just run

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

On my machine, the above output includes egrep, fgrep, zgrep, which, 7z, chromium-browser, ldd, and xfig, which I use quite often. Unless you consider your entire distribution "dirty" for relying on wrapper scripts, you have no reason to consider such wrapper scripts "dirty".


As to problems such a wrapper script may cause:

If only human users (as opposed to scripts) are using the version of grep that defaults to color support if output is to a terminal, then the wrapper script can be named colorgrep or cgrep or whatever the OP sees fit.

This avoids all possible compatibility issues, because the behaviour of grep does not change at all.


Enabling grep options with a wrapper script, but in a way that avoids any new problems:

We can easily rewrite the wrapper script to support a custom GREP_OPTS even if GREP_OPTIONS were not supported (as it is already deprecated). This way users can simply add export "GREP_OPTIONS=--color=auto" or similar to their profile. /usr/local/bin/grep is then

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

Note that there are no quotes around $GREP_OPTIONS, so that users can specify more than one option.

On my system, executing time /usr/local/bin/grep --version with GREP_OPTIONS empty, or with GREP_OPTIONS=--color=auto, is just as fast as the previous version of the wrapper script; i.e., typically takes one millisecond longer to execute than plain grep.

This last version is the one I'd personally recommend for use.


In summary, OP's strategy 4:

  • is aready recommended by grep developers

  • is trivial to implement (two lines)

  • has insignificant overhead (one millisecond extra latency per invocation on this particular laptop; easily verified on each machine)

  • can be implemented as a wrapper script that adds GREP_OPTS support (to replace deprecated/unsupported GREP_OPTIONS)

  • can be implemented (as colorgrep/cgrep) that does not affect scripts or existing users at all

Because it is a technique that is widely used in Linux distributions already, it is a common technique and not "dirty".

If implemented as a separate wrapper (colorgrep/cgrep), it cannot create new problems since it does not affect grep behaviour at all. If implemented as a wrapper script that adds GREP_OPTS support, using GREP_OPTS=--color=auto has exactly the same risks (wrt. problems with existing scripts) that upstream adding default --color=auto would. Thus, the comment that this "creates more problems than it solves" is completely incorrect: no additional problems are created.

3

The documentation you provide with first strategy says:

Please use an alias or script instead. For example, if grep is in the directory ‘/usr/bin’ you can prepend $HOME/bin to your PATH and create an executable script $HOME/bin/grep containing the following:

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

So if the alias is impossible for you, the wrapper script is the only way.

1
  • That is Strategy 4... not really an answer. – guettli Mar 14 '17 at 16:27
3

The reason the GREP_OPTIONS variable is deprecated is that it tends to cause problems when grep is called somewhere in a script and the script doesn't work with the alternative options that come from the variable. If you write a wrapper script for grep then you have the same problem, unless you give it a different name.

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

Alternatively, store your favorite options in a variable. In shells other than zsh, this is cumbersome if the options contain wildcard characters (\[*?), but otherwise you can just use the variable unquoted to get a command with arguments.

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

Note that GNU and BSD grep can process a directory tree recursively, which alleviates the need for find in combination with grep most of the time.

3
  • 1
    That is Strategy 4... not really an answer. – guettli Mar 14 '17 at 16:27
  • @guettli, that's the correct answer. If you want a command with a different behaviour that grep's, you need a command with a different name, or else if you keep the same name, you'll break scripts that expect the original/standard behaviour. That is the cleanest and doesn't cause additional trouble. – Stéphane Chazelas Mar 20 '17 at 15:19
  • @StéphaneChazelas yes you are right. This is the correct answer according to your point of view. – guettli Mar 21 '17 at 13:52
1

I realize this is an old question, but to address Strategy 3:

Strategy 3: alias. This does not work for find ... | xargs grep, since xargs does not evaluate aliases.

From help alias:

alias: alias [-p] [name[=value] ... ]
    A trailing space in VALUE causes the next word to be checked for
    alias substitution when the alias is expanded.

Therefore, make an alias for xargs with a trailing space:

alias xargs='xargs '
alias chgrep='\grep --color=auto --include=\*.{c,cc,cpp,h,hh,hpp} -r'

find /path/ -type f | xargs chgrep 'foo'
0

The easiest thing is to use an alias (strategy 3). If you really do care about the xargs command, you can still override it with a bash function.

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
}

But this is not better than using a wrapper command which seems to be the recommended solution by the grep team:

/usr/local/bin/grep:

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

In my humble opinion, you should contact the grep developer team to ask them to provide a simple replacement to the GREP_OPTIONS variable which will enable the color in grep according to some environment variable.

It would be quite simple for them to enable by default the color option or when the GREP_COLORS has been set.

2
  • 1
    Thank you for "... you should contact the grep developer team...". This gives me positive feedback. Now I know that I am not the only one who thinks something is missing here. – guettli Mar 20 '17 at 9:25
  • I added your comment "... you should contact the grep developer team..." as strategy6 to the question. Up to now this is my favourite answer. – guettli Mar 20 '17 at 9:27
0

This is the solution from the top answer by @NominalAnimal but with the usual grep: ... in warnings (instead of /bin/grep: ...):

#!/bin/bash
exec -a grep /bin/grep --color=auto "$@"
2
  • I know how to write wrappers. A wrapper is not a solution in this context. – guettli May 7 '19 at 8:11
  • @guettli Well, the answer wasn't meant to address precisely your situation... If comments had the same formatting features as answers, that would be a comment. (And I had similar edits rejected as not intended by the original author or something.) As for your situation, I think a proper literal answer to your question is: that another "Strategy NICE-and-EASY" doesn't exist. – Kirill Bulygin May 7 '19 at 8:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.