Grep regular expression stop after first match - grep

I am trying to figure out what the grep syntax would be to get one\unique result of a search.
For example :
grep "^SEVERE" server.out
SEVERE: Cannot connect repository, Error occurred when calling service PING_SERVER.
SEVERE: Cannot connect repository, Error occurred when calling service PING_SERVER.
SEVERE: Cannot connect repository, Error occurred when calling service PING_SERVER.
I would like the output to show only the first find of the that occurrence.
Any Help would be great!
tcwbot

GNU grep 2.16 which comes with cygwin has this option (from 'man grep'):
-m NUM, --max-count=NUM
Stop reading a file after NUM matching lines. If the input is
standard input from a regular file, and NUM matching lines are
output, grep ensures that the standard input is positioned to
just after the last matching line before exiting, regardless of
the presence of trailing context lines. This enables a calling
process to resume a search. When grep stops after NUM matching
lines, it outputs any trailing context lines. When the -c or
--count option is also used, grep does not output a count
greater than NUM. When the -v or --invert-match option is also
used, grep stops after outputting NUM non-matching lines.
So try:
$ grep -m 1 "^SEVERE" server.out

Related

The exit status code for the 'grep' command

The grep manual at the exit status section report:
EXIT STATUS
The exit status is 0 if selected lines are found, and 1 if not
found. If an error occurred the exit status is 2. (Note: POSIX
error handling code should check for '2' or greater.)
But the command:
echo ".
..
test.zip"|grep -vE '^[.]'
echo $?
echo "test.zip
test.txt"|grep -vE '^[.]'
echo $?
The value returned is always 0. I would have expected 1 and 0. What am I doing wrong?
Remember that grep is line based. If any line matches, you got a match. (In your first case test.zip matches (more precisely: you used with -v therefore you have asked for lines that do not match your pattern, and test.zip does exactly that, i.e. does not match your pattern. As a result your grep call was successful). Compare
$ grep -vE '^[.]' <<<$'.\na'; echo $?
a
0
with
$ grep -vE '^[.]' <<<$'.\n.'; echo $?
1
Note how the first command outputs the line a, that is it has found a match, which is why the exit status is 0. Compare that with the second example, where no line was matched.
References
<<< is a here string:
Here Strings
A variant of here documents, the format is:
[n]<<<word
The word undergoes brace expansion, tilde expansion, parameter and
variable expansion, command substitution, arithmetic expansion, and
quote removal. Pathname expansion and word splitting are not per-
formed. The result is supplied as a single string, with a newline
appended, to the command on its standard input (or file descriptor n if
n is specified).
$ cat <<<'hello world'
hello world
$'1\na' is used to get a multi line input (\n is replaced by newline within $'string', for more see man bash).
$ echo $'1\na'
1
a

Is there a way to `fgrep` with the "and" of all the passed in patterns instead of the "or"?

I want to do a search in a log file like this:
/logs/loggy.log:
INFO: cats are people
DEBUG: one doth fig're and therefore one doth be
INFO: cookies made via the catapultation of figs at an acceleration of 1 m/s^2.
INFO: informative information about my information systems
I want just the 3rd line. So I command:
grep 'cat.*fig' /logs/loggy.log
But it's a large file! Let's make it faster
grep -F -e cat -e fig /logs/loggy.log
0ops. Now I'm getting back all the lines because it now matches for either 'cat' or 'fig'. I want it to match only lines containing bolth. Is there a way to do this without going back into regular expressions land?
You can use agrep if it is available in your distro repos, which nativelly provides and operation:
$ agrep 'cat;fig' file1
Or you can use any of the following alternatives:
$ grep 'cat' file1 |grep 'fig'
$ awk '/cat/ && /fig/' file1
In all above cases the result is:
INFO: cookies made via the catapultation of figs at an acceleration of 1 m/s^2.

grep last match and it's following lines

I've learnt how to grep lines before and after the match and to grep the last match but I haven't discovered how to grep the last match and the lines underneath it.
The scenario is a server log.
I want to list a dynamic output from a command. The command is likely to be used several times in one server log. So I imagine the match would be the command and somehow grep can use -A with some other flag or variation of a tail command, to complete the outcome I'm seeking.
The approach I would take it to reverse the problem as it's easier to find the first match and print the context lines. Take the file:
$ cat file
foo
1
2
foo
3
4
foo
5
6
Say we want the last match of foo and the following to lines we could just reverse the file with tac, find the first match and n lines above using -Bn and stop using -m1. Then simple re-reverse the output with tac:
$ tac file | grep foo -B2 -m1 | tac
foo
5
6
Tools like tac and rev can make problems that seem difficult much easier.
using awk instead:
awk '/pattern/{m=$0;l=NR}l+1==NR{n=$0}END{print m;print n}' foo.log
small test, find the last line matching /8/ and the next line of it:
kent$ seq 20|awk '/8/{m=$0;l=NR}l+1==NR{n=$0}END{print m;print n}'
18
19

grepping a not matching pattern with a pattern file and data from a pipe

I have an ignore.txt file:
cat ignore.txt
clint
when I do:
pip freeze | grep -v -f ignore.txt
I get:
GitPython==0.3.2.RC1
Markdown==2.2.1
async==0.6.1
clint==0.3.1
gitdb==0.5.4
legit==0.1.1
push-to-wordpress==0.1
python-wordpress-xmlrpc==2.2
smmap==0.8.2
but when I do:
pip freeze | grep -v clint
I do get the correct output:
GitPython==0.3.2.RC1
Markdown==2.2.1
async==0.6.1
gitdb==0.5.4
legit==0.1.1
push-to-wordpress==0.1
python-wordpress-xmlrpc==2.2
smmap==0.8.2
How can I achieve that with grep and command line tools?
Clarfication Edit: I use windows with cygwin so I believe this is GNU grep 2.6.3 (from grep --version)
Your syntax looks correct and works on my system.
There may be a problem with your ignore.txt file.
In particular, check that:
there are no leading or trailing spaces, tabs and the like around the word you are trying to filter (as suggested by Kent above)
the file has Unix line endings
the file is terminated by a single newline
About the latter, the Single Unix Specification says:
Patterns in pattern_file shall be terminated by a <newline>.
Which means that a file with no terminator, or with a different terminator (e.g. CR LF), might behave unexpectedly (though that might be system-dependent).

grep is unable to find all pattern matching "\[\[\[\["

I am having problems with using grep along with a pipe. The scenario is as follows:
I am running a python script that outputs (using print) to the screen debug messages. I use ./prog | grep "\[\[\[\[" to catch the strings with "[[[[" in them. It returns few matching results but not others (Another observation: results found by grep come before the results not found by grep in the file). I have ran the ./prog without pipe and grep and it outputs all the strings with "[[[[" pattern.
The problem is that the left square bracket is a special character in regular expressions. "grep" is not just a string matcher. Regular expressions are an involved language that let you describe patterns of text. Grep is trying to interpret [[[[ as a regular expression, not just a string.
As your question subject suggests, you can usually escape special characters with a backslash. So the following might work:
./prog | grep '\[\[\[\['
You can also "escape" square brackets by putting them inside square brackets. Thus, [[][[][[][[] or [[]{4} if your version of grep handles it.
You also need to determine whether your program, ./prog, is sending output to "standard output" or "standard error". You can put all your stderr through the pipe with:
./proc 2>&1 | egrep '[[]{4}'
UPDATE:
[ghoti#pc ~]$ printf '[[[[\n[[[\n[[[[\n[[[[[\n[[\n' | grep '\[\[\[\['
[[[[
[[[[
[[[[[
[ghoti#pc ~]$ printf '[[[[\n[[[\n[[[[\n[[[[[\n[[\n' | egrep '[[]{4}'
[[[[
[[[[
[[[[[
[ghoti#pc ~]$
Obviously, my results do not match yours. If you can provide more details as to the data you're processing, it will be helpful in trying to duplicate your results.
Error messages are usually sent to stderr, not stdout; your pipe is filtering stdout. (Your "another observation" hints at this.) You can redirect stderr along with stdout to the pipe:
./prog 2>&1 | grep '\[\[\[\['

Resources