Bash Grep exact search - bash

I am trying to find an exact word in a file. The word is myServer and the file contents in which I am trying to find it are:
This is myServer and it is cool
This is myServer-test and it is cool
Here're the results of my various attempts to do this:
grep '^myServer$' test-file.txt
grep -Fx myServer test-file.txt
--> no results
grep -w myServer test-file.txt
grep -w myServer test-file.txt
grep '\<myServer\>' test-file.txt
grep '\bmyServer\b' test-file.txt
-->
This is myServer and it is cool
This is myServer-test and it is cool
Am I missing some switch here?
Many Thanks.

Try grep with word boundaries:
grep '\<myServer\>' test-file.txt
EDIT: Looks like you don't want to treat hyphen as word boundary. Use grep like this for that purpose:
grep -E '\<myServer\>([^-]|$)' test-file.txt

You can use \< and \> to identify beginning and end of words. So for example given \<myS to grep would search for lines with a word starting with myS.
Naturally, to search for an exact word, you would search like this:
grep '\<myServer\>' test-file.txt
In most of your attempts, you are doing completely irrelevant stuff:
^ and $ match the beginning and end of the line.
-F searches for multiple fixed strings
-x searches for whole lines matching the regex
Note: your -w would work correctly. However, it seems that your definition of "whole word" is different from what POSIX thinks.

You can use \b which means a word boundary:
rep '\bmyServer\b' test-file.txt

Related

Colorize specific strings in a text

I would like to highlight a few strings while outputting a text file. For example the literals [2], quick and lazy in:
... => any number of lines with non-matching content
He’s quick but lazy.
...
• The future belongs to those who believe in the beauty of their dreams [2].
...
I’m lazy but quick (2 times faster); is there a difference when "lazy" comes before "quick"?
...
My intuitive approach would be to use grep for the colorization (in fact I'm not fixed on any specific tool):
grep -F -e '[2]' -e 'quick' -e 'lazy' --color file.txt
But it has two problems:
It filters out the lines that don't match while I want to include them in the output.
It doesn't highlight all the matching strings; it seems like the order in which the -e expressions are provided matters (problem noticed with macOS grep).
My expected output (with <...> standing for the colorization) would be:
... => any number of lines with non-matching content
He’s <quick> but <lazy>.
...
• The future belongs to those who believe in the beauty of their dreams <[2]>.
...
I’m <lazy> but <quick> (2 times faster); is there a difference when "<lazy>" comes before "<quick>"?
...
grep -n -F -e '[2]' -e 'quick' -e 'lazy' --color=always file.txt |
awk -F':' '
FILENAME==ARGV[1] { n=substr($1,9,length($1)-22); sub(/[^:]+:/,""); a[n]=$0; next }
{ print (FNR in a ? a[FNR] : $0) }
' - file.txt
would use grep to find and highlight the strings, and then awk would print the grep output for those lines and the original lines from the input file otherwise.
UPDATE
I found a way using grep -E instead of grep -F. As a side-effect, matching a literal string will require its ERE-escaping.
The method is to build a single regex composed of the union of the search strings plus an additional $ anchor (for selecting the "non-matching" lines).
Hence, for highlighting the literals [2], quick and lazy in the sample text, you can use:
grep -E '\[2]|quick|lazy|$' --color file.txt
edit: I replaced the ^ anchor with the $ one because on macOS:
grep -E '\[2]|quick|lazy|^' --color doesn't highlight any word
grep -E -e '\[2]|quick|lazy' -e '^' --color SEGFAULTS !!!

Grep multiple strings from text file

Okay so I have a textfile containing multiple strings, example of this -
Hello123
Halo123
Gracias
Thank you
...
I want grep to use these strings to find lines with matching strings/keywords from other files within a directory
example of text files being grepped -
123-example-Halo123
321-example-Gracias-com-no
321-example-match
so in this instance the output should be
123-example-Halo123
321-example-Gracias-com-no
With GNU grep:
grep -f file1 file2
-f FILE: Obtain patterns from FILE, one per line.
Output:
123-example-Halo123
321-example-Gracias-com-no
You should probably look at the manpage for grep to get a better understanding of what options are supported by the grep utility. However, there a number of ways to achieve what you're trying to accomplish. Here's one approach:
grep -e "Hello123" -e "Halo123" -e "Gracias" -e "Thank you" list_of_files_to_search
However, since your search strings are already in a separate file, you would probably want to use this approach:
grep -f patternFile list_of_files_to_search
I can think of two possible solutions for your question:
Use multiple regular expressions - a regular expression for each word you want to find, for example:
grep -e Hello123 -e Halo123 file_to_search.txt
Use a single regular expression with an "or" operator. Using Perl regular expressions, it will look like the following:
grep -P "Hello123|Halo123" file_to_search.txt
EDIT:
As you mentioned in your comment, you want to use a list of words to find from a file and search in a full directory.
You can manipulate the words-to-find file to look like -e flags concatenation:
cat words_to_find.txt | sed 's/^/-e "/;s/$/"/' | tr '\n' ' '
This will return something like -e "Hello123" -e "Halo123" -e "Gracias" -e" Thank you", which you can then pass to grep using xargs:
cat words_to_find.txt | sed 's/^/-e "/;s/$/"/' | tr '\n' ' ' | dir_to_search/*
As you can see, the last command also searches in all of the files in the directory.
SECOND EDIT: as PesaThe mentioned, the following command would do this in a much more simple and elegant way:
grep -f words_to_find.txt dir_to_search/*

Using egrep to search for IP address by octets from a shell variable

I'm writing a BASH script that outputs iptables -L -n and searches for the existence of an IP address. I'm stuck with how to use this with egrep. Roughly:
CHECK=$(iptables -L -n | egrep $the_string)
which "looks" like it would work, but it doesn't have an end delimiter $ so it would match:
25.24.244
and
25.24.24
When I really just need to match for 25.24.24 only.
I tried escaping this but the $ creates issues with the regular expression.
At least this is the only means I've found to search for the IP in the iptables system. It doesn't appear to have any query mechanism itself (puzzling).
I am probably missing something very simple here, and just need a pointer or two :-)
Thanks.
You should backslash the . : this means any character in regex...
iptables -L -n | grep "25\.24\.24$"
(no need egrep there)
The $ at the end of the regular expression works as expected:
the_ip=25.24.24
the_string=$(echo $the_ip | sed 's/\./\\\./g')
iptables -L -n | egrep "$the_string$"

grep like command to find matching lines plus neighbourhood lines

grep command is really powerful and I use it a lot.
Sometime I have the necessity to find something with grep looking inside many many files to find the string I barely remember helping myself with -i (ignore case) option, -r (recursive) and also -v (exclude).
But what I really need is to have a special output from grep which highlight the matching line(s) plus the neighbourhood lines (given the matching line I'd like to see, let's say, the 2 preceding and the 2 subsequent lines).
Is there a way to get this result using bash?
Grep itself will do this
grep -A 2 -B 2 foo myfile.txt
most greps allow the "context" flag making it a bit more readable:
grep --context=3 foo myfile.txt
You can omit -C
grep -2 foo myfile.txt
is equal to
grep -C 2 foo myfile.txt

bash grep newline

[Editorial insertion: Possible duplicate of the same poster's earlier question?]
Hi, I need to extract from the file:
first
second
third
using the grep command, the following line:
second
third
How should the grep command look like?
Instead of grep, you can use pcregrep which supports multiline patterns
pcregrep -M 'second\nthird' file
-M allows the pattern to match more than one line.
Your question abstract "bash grep newline", implies that you would want to match on the second\nthird sequence of characters - i.e. something containing newline within it.
Since the grep works on "lines" and these two are different lines, you would not be able to match it this way.
So, I'd split it into several tasks:
you match the line that contains "second" and output the line that has matched and the subsequent line:
grep -A 1 "second" testfile
you translate every other newline into the sequence that is guaranteed not to occur in the input. I think the simplest way to do that would be using perl:
perl -npe '$x=1-$x; s/\n/##UnUsedSequence##/ if $x;'
you do a grep on these lines, this time searching for string ##UnUsedSequence##third:
grep "##UnUsedSequence##third"
you unwrap the unused sequences back into the newlines, sed might be the simplest:
sed -e 's/##UnUsedSequence##/\n'
So the resulting pipe command to do what you want would look like:
grep -A 1 "second" testfile | perl -npe '$x=1-$x; s/\n/##UnUsedSequence##/ if $x;' | grep "##UnUsedSequence##third" | sed -e 's/##UnUsedSequence##/\n/'
Not the most elegant by far, but should work. I'm curious to know of better approaches, though - there should be some.
I don't think grep is the way to go on this.
If you just want to strip the first line from any file (to generalize your question), I would use sed instead.
sed '1d' INPUT_FILE_NAME
This will send the contents of the file to standard output with the first line deleted.
Then you can redirect the standard output to another file to capture the results.
sed '1d' INPUT_FILE_NAME > OUTPUT_FILE_NAME
That should do it.
If you have to use grep and just don't want to display the line with first on it, then try this:
grep -v first INPUT_FILE_NAME
By passing the -v switch, you are telling grep to show you everything but the expression that you are passing. In effect show me everything but the line(s) with first in them.
However, the downside is that a file with multiple first's in it will not show those other lines either and may not be the behavior that you are expecting.
To shunt the results into a new file, try this:
grep -v first INPUT_FILE_NAME > OUTPUT_FILE_NAME
Hope this helps.
I don't really understand what do you want to match. I would not use grep, but one of the following:
tail -2 file # to get last two lines
head -n +2 file # to get all but first line
sed -e '2,3p;d' file # to get lines from second to third
(not sure how standard it is, it works in GNU tools for sure)
So you just don't want the line containing "first"? -v inverts the grep results.
$ echo -e "first\nsecond\nthird\n" | grep -v first
second
third
Line? Or lines?
Try
grep -E -e '(second|third)' filename
Edit: grep is line oriented. you're going to have to use either Perl, sed or awk to perform the pattern match across lines.
BTW -E tell grep that the regexp is extended RE.
grep -A1 "second" | grep -B1 "third" works nicely, and if you have multiple matches it will even get rid of the original -- match delimiter
grep -E '(second|third)' /path/to/file
egrep -w 'second|third' /path/to/file
you could use
$ grep -1 third filename
this will print a string with match and one string before and after. Since "third" is in the last string you get last two strings.
I like notnoop's answer, but building on AndrewY's answer (which is better for those without pcregrep, but way too complicated), you can just do:
RESULT=`grep -A1 -s -m1 '^\s*second\s*$' file | grep -s -B1 -m1 '^\s*third\s*$'`
grep -v '^first' filename
Where the -v flag inverts the match.

Resources