I'd like find lines in files with an occurrence of some pattern and an absence of some other pattern. For example, I need find all files/lines including loom
except ones with gloom
. So, I can find loom
with command:
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
Now, I want to search loom
excluding gloom
. However, both of following commands failed:
grep -v 'gloom' -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
grep -n 'loom' -v 'gloom' ~/projects/**/trunk/src/**/*.@(h|cpp)
What should I do to achieve my goal?
EDIT 1: I mean that loom
and gloom
are the character sequences (not necessarily the words). So, I need, for example, bloomberg
in the command output and don't need ungloomy
.
EDIT 2: There is sample of my expectations. Both of following lines are in command output:
I faced the icons that loomed through the veil of incense.
Arty is slooming in a gloomy day.
Both of following lines aren't in command output:
It’s gloomyin’ ower terrible — great muckle doolders o’ cloods.
In the south west round of the heigh pyntit hall
Specify Multiple Patterns. The -e flag allows us to specify multiple patterns through repeated use. We can exclude various patterns using the -v flag and repetition of the -e flag: $ grep -ivw -e 'the' -e 'every' /tmp/baeldung-grep Time for some thrillin' heroics.
grep is very often used as a "filter" with other commands. It allows you to filter out useless information from the output of commands. To use grep as a filter, you must pipe the output of the command through grep . The symbol for pipe is " | ".
Case Insensitive Search By default, grep is case sensitive. This means that the uppercase and lowercase characters are treated as distinct. To ignore case when searching, invoke grep with the -i option (or --ignore-case ).
How about just chaining the greps?
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
Another solution without chaining grep
:
egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
Between brackets, you exclude the character g
before any occurrence of loom
, unless loom
is the first chars of the line.
A bit old, but oh well...
The most up-voted solution from @houbysoft will not work as that will exclude any line with "gloom" in it, even if it has "loom". According to OP's expectations, we need to include lines with "loom", even if they also have "gloom" in them. This line needs to be in the output "Arty is slooming in a gloomy day.", but this will be excluded by a chained grep like
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
Instead, the egrep regex example of Bentoy13 works better
egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
as it will include any line with "loom" in it, regardless of whether or not it has "gloom". On the other hand, if it only has gloom, it will not include it, which is precisely the behaviour OP wants.
Just use awk, it's much simpler than grep in letting you clearly express compound conditions.
If you want to skip lines that contains both loom
and gloom
:
awk '/loom/ && !/gloom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)
or if you want to print them:
awk '/(^|[^g])loom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)
and if the reality is you just want lines where loom
appears as a word by itself:
awk '/\<loom\>/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)
-v
is the "inverted match" flag, so piping is a very good way:
grep "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)| grep -v "gloom"
Simply use! grep -v
multiple times.
#Content of file
[root@server]# cat file
1
2
3
4
5
#Exclude the line or match
[root@server]# cat file |grep -v 3
1
2
4
5
#Exclude the line or match multiple
[root@server]# cat file |grep -v "3\|5"
1
2
4
/*You might be looking something like this?
grep -vn "gloom" `grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)`
The BACKQUOTES are used like brackets for commands, so in this case with -l
enabled,
the code in the BACKQUOTES will return you the file names, then with -vn to do what you wanted: have filenames, linenumbers, and also the actual lines.
UPDATE Or with xargs
grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp) | xargs grep -vn "gloom"
Hope that helps.*/
Please ignore what I've written above, it's rubbish.
grep -n "loom" `grep -l "loom" tt4.txt` | grep -v "gloom"
#this part gets the filenames with "loom"
#this part gets the lines with "loom"
#this part gets the linenumber,
#filename and actual line
You can use grep -P
(perl regex) supported negative lookbehind
:
grep -P '(?<!g)loom\b' ~/projects/**/trunk/src/**/*.@(h|cpp)
I added \b
for word boundaries.
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With