Reputation: 5941
I'm searching a directory recursively using grep with the following arguments hoping to only return the first match. Unfortunately, it returns more than one -- in-fact two the last time I looked. It seems like I have too many arguments, especially without getting the desired outcome. :-/
# grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/directory
returns:
Pulsanti Operietur
Pulsanti Operietur
Maybe grep isn't the best way to do this? You tell me, thanks very much.
Upvotes: 584
Views: 857622
Reputation: 2889
Reading the grep manual (man grep) this is the minimum command to find first match with Extended regexp. Example getting the ethernet name that in my laptop is NOT eth0!
$ ifconfig | grep -E -o -m 1 "^[a-z0-9]+"
Explanation:
-E for extended regexp,
-o to return just the match itself,
-m 1 to look for only one match
Upvotes: 8
Reputation: 4093
ugrep supports this via --max-files
:
--max-files=NUM
Restrict the number of files matched to NUM. Note that --sort or -J1 may be specified to produce replicable results. If --sort is specified, the number of threads spawned is limited to NUM.
Related:
Upvotes: 2
Reputation: 1010
For anyone who lands here, as I did, perplexed as to why --max-count
didn't seem to be working when acting on stdin
...
TL;DR - --max-count n
does NOT stop after finding n
matches, it stops after finding all matches on n
lines.
(And stdin
, even if it's only a string, counts as one line.)
This is true despite the fact that, in zsh 5.8
, at least, man grep
describes the option this way:
-m num, --max-count=num
Stop reading the file after num matches.
Longer Explanation
In my case, I was trying to grab just the first part of a relative path (some
in the example below):
> echo "some/path/here" | grep -E -o -m 1 '[^\/]+'
and was quite confused when it gave me back
some
path
here
Thanks to the comment from @harperville above, I finally figured out: It's not about the output, it's about the input.
Indeed, when I tried
> echo "some/path/here \n another/path/there" | grep -E -o -m 1 '[^\/]+'
I got the same result as above (i.e., only the parts before the \n
in this second example).
Notes
For those who are less familiar with grep
:
-E
(--extended-regexp
) tells it to use "extended" regular expressions, i.e., the ones you're used to from most other programming languages. The differences between "extended" and "basic" aren't big - it's just about which characters you need to escape in your regex - but as someone who's primarily a TS and Python developer, I always use -E
because that way I never have to think about it. (Pro-tip: Add alias grep="grep -E"
to your .zshrc
and you'll never have to worry about it again!)-o
(--only-matching
) tells it to only print the matches, rather than each line on which it found a match.-m n
(--max-count n
) restricts it to returning matches from n
lines. (If you've read this far you clearly already know that, though! 😛)Upvotes: 44
Reputation: 8141
A single liner, using find
:
find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit
Upvotes: 0
Reputation: 247
You can use below command if you want to print entire line and file name if the occurrence of particular word in current directory you are searching.
grep -m 1 -r "Not caching" * | head -1
Upvotes: 23
Reputation: 10743
You can pipe grep
result to head
in conjunction with stdbuf.
Note, that in order to ensure stopping after Nth match, you need to using stdbuf
to make sure grep
don't buffer its output:
stdbuf -oL grep -rl 'pattern' * | head -n1
stdbuf -oL grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -n1
stdbuf -oL grep -nH -m 1 -R "django.conf.urls.defaults" * | head -n1
As soon as head
consumes 1 line, it terminated and grep
will receive SIGPIPE
because it still output something to pipe while head
was gone.
This assumed that no file names contain newline.
Upvotes: 52
Reputation: 116048
-m 1
means return the first match in any given file. But it will still continue to search in other files. Also, if there are two or more matched in the same line, all of them will be displayed.
head -1
to solve this problem:grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -1
-o, --only-matching, print only the matched part of the line (instead of the entire line)
-a, --text, process a binary file as if it were text
-m 1, --max-count, stop reading a file after 1 matching line
-h, --no-filename, suppress the prefixing of file names on output
-r, --recursive, read all files under a directory recursively
Upvotes: 832
Reputation: 93636
My grep-a-like program ack
has a -1
option that stops at the first match found anywhere. It supports the -m 1
that @mvp refers to as well. I put it in there because if I'm searching a big tree of source code to find something that I know exists in only one file, it's unnecessary to find it and have to hit Ctrl-C.
Upvotes: 24