Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to grep and match the first occurrence of a line?

Tags:

grep

shell

Given the following content:

title="Bar=1; Fizz=2; Foo_Bar=3;"

I'd like to match the first occurrence of Bar value which is 1. Also I don't want to rely on soundings of the word (like double quote in the front), because the pattern could be in the middle of the line.

Here is my attempt:

$ grep -o -m1 'Bar=[ ./0-9a-zA-Z_-]\+' input.txt
Bar=1
Bar=3

I've used -m/--max-count which suppose to stop reading the file after num matches, but it didn't work. Why this option doesn't work as expected?

I could mix with head -n1, but I wondering if it is possible to achieve that with grep?

like image 407
kenorb Avatar asked Sep 13 '25 12:09

kenorb


2 Answers

Using perl based regex flavor in gnu grep you can use:

grep -oP '^(.(?!Bar=\d+))*Bar=\d+' <<< "Bar=1; Fizz=2; Foo_Bar=3;"
Bar=1

(.(?!Bar=\d+))* will match 0 or more of any characters that don't have Bar=\d+ pattern thus making sure we match first Bar=\d+

If intent is to just print the value after = then use:

grep -oP '^(.(?!Bar=\d+))*Bar=\K\d+' <<< "Bar=1; Fizz=2; Foo_Bar=3;"
1
like image 125
anubhava Avatar answered Sep 16 '25 07:09

anubhava


grep is line-oriented, so it apparently counts matches in terms of lines when using -m[1] - even if multiple matches are found on the line (and are output individually with -o).

While I wouldn't know to solve the problem with grep alone (except with GNU grep's -P option - see anubhava's helpful answer), awk can do it (in a portable manner):

$ awk -F'Bar=|;' '{ print $2 }' <<<"Bar=1; Fizz=2; Foo_Bar=3;"
1

Use print "Bar=" $2, if the field name should be included.
Also note that the <<< method of providing input via stdin (a so-called here-string) is specific to Bash, Ksh, Zsh; if POSIX compliance is a must, use echo "..." | grep ... instead.


[1] Options -m and -o are not part of the grep POSIX spec., but both GNU and BSD/OSX grep support them and have chosen to implement the line-based logic.
This is consistent with the standard -c option, which counts "selected lines", i.e., the number of matching lines:
grep -o -c 'Bar=[ ./0-9a-zA-Z_-]\+' <<<"Bar=1; Fizz=2; Foo_Bar=3;" yields 1.

like image 35
mklement0 Avatar answered Sep 16 '25 09:09

mklement0