336

When using grep, it will highlight any text in a line with a match to your regular expression.

What if I want this behaviour, but have grep print out all lines as well? I came up empty after a quick look through the grep man page.

Martin Konecny
  • 57,827
  • 19
  • 139
  • 159
  • Za? The `grep` I know just outputs the matching lines. What is this highlighting you speak of? – Tom Zych Sep 12 '11 at 20:56
  • as a quick solution, use -A and -B, se to a high enough value you will see all lines. Proper solution is to probably use sed/perl/awk etc, to add color-escape-codes around matching word only – Fredrik Pihl Sep 12 '11 at 20:56
  • 3
    @TomZych Not sure if you're being serious, but some distros don't have color enabled by default. Try the --color option – Martin Konecny Oct 25 '12 at 16:28

10 Answers10

353

Use ack. Check out its --passthru option here: ack. It has the added benefit of allowing full Perl regular expressions.

    $ ack --passthru 'pattern1' file_name

    $ command_here | ack --passthru 'pattern1'

You can also do it using grep like this:

    $ grep --color -E '^|pattern1|pattern2' file_name

    $ command_here | grep --color -E '^|pattern1|pattern2'

This will match all lines and highlight the patterns. The ^ matches every start of the line but won't get printed/highlighted since it's not a character.

(Note that most of the setups will use --color by default. You may not need that flag).

AsukaMinato
  • 1,017
  • 12
  • 21
holygeek
  • 15,653
  • 1
  • 40
  • 50
  • 11
    This doesn't work with all flavors of grep. Some `grep`s optimize the pattern for fastest match. Mac OS X Mountain Lion switched to a BSD-style grep for which this doesn't work. The optimized expression matches all lines, but nothing is highlighted. – willkil Dec 20 '12 at 19:10
  • 2
    As for @willkil, the grep version does not work for me. The only solution here was the **ack** approach. – ricab Jun 11 '13 at 12:48
  • 2
    The following worked for me: `grep --color -E '(^|pattern1|pattern2)' file name`. In some flavours of grep + other regexes do OR matching on patterns it needs to be inside brackets. – uNople Jun 20 '13 at 23:49
  • @uNople Adding the parens does not help on OSX Mountain Lion. I created a file that simply numbered lines 1..100000, then did `grep --color -E '(^|888|999)'`. The output was identical to the output from omitting the parens: Many lines were highlighted, but 99888 was _not_ highlighted. – willkil Jul 01 '13 at 20:50
  • 12
    My previous comment lead me to think of trying `grep --color -E '888|999|$'`: It works! The difference must be in using a [text- vs regex-directed](http://www.regular-expressions.info/engine.html) regex engine. – willkil Jul 01 '13 at 20:54
  • The grep hack works for me and it's pretty. For those not so familiar with regexps, ^ will match any beginning of a line (that's why EVERYTHING gets printed) but, since it's not a visible character, it won't get highlighted. Then the first pipe (|) followed by your match is required. The second pipe (and any other you may need) are optional. Also, works for commands, removing the `file name` -> ls | grep --color -E '^|pattern' – Roberto Decurnex Jun 30 '14 at 20:06
  • 13
    With OSX grep, ``grep --color -E 'pattern1|$'`` works – Wes Turner Dec 09 '14 at 22:19
  • 1
    [`ripgrep`](https://github.com/BurntSushi/ripgrep) has also got a `--passthru` option. – Frederick Zhang Aug 05 '20 at 00:08
  • The `^|` is genius! It's even possible `grep -E '|pattern'`! (no `^`), `grep (GNU grep) 3.1, 2017` – Artfaith Oct 25 '20 at 16:09
  • [ag](https://github.com/ggreer/the_silver_searcher) also has this option (it can be spelled `passthru` or `passthrough`). – Zac Anger Jan 29 '21 at 00:31
125

You can make sure that all lines match but there is nothing to highlight on irrelevant matches

egrep --color 'apple|' test.txt 

Notes:

  • egrep may be spelled also grep -E
  • --color is usually default in most distributions
  • some variants of grep will "optimize" the empty match, so you might want to use "apple|$" instead (see: https://stackoverflow.com/a/13979036/939457)
Sorin
  • 5,201
  • 2
  • 18
  • 45
  • 5
    Great. All the magic is in the pipe char. Thanks very much! – Albus Dumbledore Aug 21 '12 at 08:28
  • 4
    Like the @holygeek's answer, this doesn't work for all `grep`s. All lines match but nothing is highlighted. – willkil Dec 20 '12 at 19:12
  • 3
    You don't need the `-i` (case insensitive matches) there. Also, `--color` is the default in most of the setups, you may not need that. `grep -E` works just like `egrep`. It will also work for command outputs like `ls | egrep 'pattern|'. The pipe can go after or before any pattern `|pattern'. You can use a set of patters adding more pipes `pattarn1|pattern2|`. – Roberto Decurnex Jun 30 '14 at 20:21
  • @willkil works for me with `grep (GNU grep) 3.4` on `Ubuntu 20.04.4`. – Lenormju Jul 21 '22 at 14:23
  • 1
    @Lenormju Yes, GNU `grep` also worked in 2012 when I commented. See [my answer below](https://stackoverflow.com/a/13979036/1086034) for more details. – willkil Jul 23 '22 at 18:27
43

EDIT:

This works with OS X Mountain Lion's grep:

    grep --color -E 'pattern1|pattern2|$'

This is better than '^|pattern1|pattern2' because the ^ part of the alternation matches at the beginning of the line whereas the $ matches at the end of the line. Some regular expression engines won't highlight pattern1 or pattern2 because ^ already matched and the engine is eager.

Something similar happens for 'pattern1|pattern2|' because the regex engine notices the empty alternation at the end of the pattern string matches the beginning of the subject string.

[1]: http://www.regular-expressions.info/engine.html

FIRST EDIT:

I ended up using Perl:

    perl -pe 's:pattern:\033[31;1m$&\033[30;0m:g'

This assumes you have an ANSI-compatible terminal.

ORIGINAL ANSWER:

If you're stuck with a strange grep, this might work:

    grep -E --color=always -A500 -B500 'pattern1|pattern2' | grep -v '^--'

Adjust the numbers to get all the lines you want.

The second grep just removes extraneous -- lines inserted by the BSD-style grep on Mac OS X Mountain Lion, even when the contexts of consecutive matches overlap.

I thought GNU grep omitted the -- lines when context overlaps, but it's been a while so maybe I remember wrong.

willkil
  • 1,619
  • 1
  • 21
  • 33
  • 4
    @sorin: Yes, but the question was also about highlighting matching lines while printing all lines, which simply isn't possible with all `grep`s. In particular, the selected answer and _your answer_ **don't work** on OSX Mountain Lion. – willkil Jan 29 '13 at 17:38
  • +1 This doesn't deserve the downvotes, and at least it DOES work on OSX 10.7^ – ocodo Mar 07 '13 at 04:34
  • Works on Big Sur with two patterns (not three though) `grep --color -E '$|master|main|$'` – rtc11 Jun 02 '21 at 08:36
  • @rtc11 Strange. I have no problems with three, four, five alternates on Big Sur 11.3.1. Your example looks fine. ¯\\_(ツ)_/¯ – willkil Jun 03 '21 at 13:00
  • Why is this answer and similar ones getting upvotes? It does not answer the original question! The author of the question don't want to filter out text!!! This is an incorrect answer that got many upvotes, so frustrating so see this. – Alexandre V. May 13 '22 at 12:30
  • @AlexandreV. This doesn't filter. The regular expression matches all lines in all `grep`s I know, but only color highlights the desired text. – willkil May 14 '22 at 15:49
39

You can use my highlight script from https://github.com/kepkin/dev-shell-essentials

It's better than grep cause you can highlight each match with it's own color.

$ command_here | highlight green "input" | highlight red "output"

enter image description here

kepkin
  • 1,105
  • 11
  • 14
  • This seems helpful, but it didn't work on my debian box even after changing the shebang at the top =( Do I need more than just highlight.sh? – Ninjaxor Apr 23 '16 at 18:20
  • Works great! Love it. Worth mentioning that it would be best to include the script into your ~/.bashrc, and remove the word "function". This way it works as a function from shell. – Adashi Sep 26 '17 at 10:00
  • This also makes a perfect function for e.g. my .zshrc – Jounathaen Apr 17 '18 at 13:22
27

Since you want matches highlighted, this is probably for human consumption (as opposed to piping to another program for instance), so a nice solution would be to use:

less -p <your-pattern> <your-file>

And if you don't care about case sensitivity:

less -i -p <your-pattern> <your-file>

This also has the advantage of having pages, which is nice when having to go through a long output

acros
  • 456
  • 5
  • 11
4

You can do it using only grep by:

  1. reading the file line by line
  2. matching a pattern in each line and highlighting the pattern by grep
  3. if there is no match, echo the line as is

which gives you the following:

while read line ; do (echo $line | grep PATTERN) || echo $line  ; done < inputfile
AsukaMinato
  • 1,017
  • 12
  • 21
jackhab
  • 17,128
  • 37
  • 99
  • 136
3

If you want to print "all" lines, there is a simple working solution:

grep "test" -A 9999999 -B 9999999
  • A => After
  • B => Before
AsukaMinato
  • 1,017
  • 12
  • 21
Leon X. W.
  • 721
  • 5
  • 8
  • 1
    This way the file get echoed completely every time grep has a match, which is very likely not what you want. – sjas Feb 20 '15 at 09:15
  • 2
    @sjas Er, isn't that *exactly* what OP wants? – Kyle Strand Oct 23 '15 at 16:09
  • @Kyle Strand, the OP wants to be able to print the entire file; with this solution, if a given file has ten matches for "test", this solution will print the file ten times, which might not be what the OP wants. – alpheus Oct 26 '16 at 20:36
  • @user993865 Did you test it? That is not the case. (I.e., `grep` does *not* print any lines more than once.) – Kyle Strand Oct 26 '16 at 20:56
  • 1
    this will not work if no matches at all – Brook Dec 27 '18 at 01:28
-1

If you are looking for a pattern in a directory recursively, you can either first save it to file.

ls -1R ./ | list-of-files.txt

And then grep that, or pipe it to the grep search

ls -1R | grep --color -rE '[A-Z]|'

This will look of listing all files, but colour the ones with uppercase letters. If you remove the last | you will only see the matches.

I use this to find images named badly with upper case for example, but normal grep does not show the path for each file just once per directory so this way I can see context.

tristanbailey
  • 4,427
  • 1
  • 26
  • 30
  • As far as I can tell, the only part of this that actually answers the question is the end-of-pattern pipe character, which was already demonstrated in at least two other answers when you posted this. – Kyle Strand Oct 23 '15 at 16:10
-1

If you are doing this because you want more context in your search, you can do this:

cat BIG_FILE.txt | less

Doing a search in less should highlight your search terms.

Or pipe the output to your favorite editor. One example:

cat BIG_FILE.txt | vim -

Then search/highlight/replace.

dgo.a
  • 2,634
  • 23
  • 35
-3

Maybe this is an XY problem, and what you are really trying to do is to highlight occurrences of words as they appear in your shell. If so, you may be able to use your terminal emulator for this. For instance, in Konsole, start Find (ctrl+shift+F) and type your word. The word will then be highlighted whenever it occurs in new or existing output until you cancel the function.

Community
  • 1
  • 1
Roger Dahl
  • 15,132
  • 8
  • 62
  • 82
  • 1
    Even if highlighting occurrences of words as they appear were the "real" need, this is not a generic solution. Even the find function for GNOME terminal (a similarly rich emulator) does not appear to behave this way (shifting focus back to the prompt immediately un-highlights the search pattern). And in any case, I'm not convinced that this is an XY problem. – Kyle Strand Oct 23 '15 at 16:05