(I'm assuming you intended the second grep
to match on the content of line and not on the file names or both as your approach was doing)
POSIXly:
find . -type f -exec awk '
FNR == 1 {found = 0}
!found && tolower($0) ~ /some string/ && /other string/ {
print FILENAME
found = 1
nextfile
}' {} +
The business about found
is for awk implementations that don't support nextfile
yet (and where nextfile
is then a no-op). If you know your awk
implementation supports nextfile
, you can simplify it to:
find . -type f -exec awk 'tolower($0) ~ /some string/ && /other string/ {
print FILENAME; nextfile}' {} +
With GNU grep
built with PCRE support, since you want one match to be case insensitive and not the other:
grep -rlP '^(?=.*(?i:some string))(?=.*other string)' .
(?=...)
is a perl look-ahead operator. (?i:pattern)
turns on case-insensitive match for pattern
only. So here we're matching on the beginning of the line (^
) provided it's followed by any number of characters (.*
) followed by some string
(case insensitive) and also that it (the beginning of the line) is followed by any number of characters and other string
(case sensitive).
If your grep
doesn't support -P
, you may have the pcregrep
command instead (replace grep -rlP
with pcregrep -rl
), or if the patterns don't overlap, you could do:
grep -rl -e '[sS][oO][mM][eE] [sS][tT][rR][iI][nN][gG].*other string' \
-e 'other string.*[sS][oO][mM][eE] [sS][tT][rR][iI][nN][gG]' .
Or if you don't care both matches being case insensitive:
grep -ril -e 'some string.*other string' \
-e 'other string.*some string' .
-i
of the initialgrep
) - I'm retracting my close vote – don_crissti Apr 20 '17 at 13:19