How to Find Lines Containing a String in Linux

How to find lines containing a string in linux

The usual way to do this is with grep, which uses a regex pattern to match lines:

grep 'pattern' file

Each line which matches the pattern will be output. If you want to search for fixed strings only, use grep -F 'pattern' file. fgrep is shorthand for grep -F.


You can also use sed:

sed -n '/pattern/p' file

Or awk:

awk '/pattern/' file

How to find all files containing specific text (string) on Linux?

Do the following:

grep -rnw '/path/to/somewhere/' -e 'pattern'
  • -r or -R is recursive,
  • -n is line number, and
  • -w stands for match the whole word.
  • -l (lower-case L) can be added to just give the file name of matching files.
  • -e is the pattern used during the search

Along with these, --exclude, --include, --exclude-dir flags could be used for efficient searching:

  • This will only search through those files which have .c or .h extensions:

    grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
  • This will exclude searching all the files ending with .o extension:

    grep --exclude=\*.o -rnw '/path/to/somewhere/' -e "pattern"
  • For directories it's possible to exclude one or more directories using the --exclude-dir parameter. For example, this will exclude the dirs dir1/, dir2/ and all of them matching *.dst/:

    grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/search/' -e "pattern"

This works very well for me, to achieve almost the same purpose like yours.

For more options, see man grep.

Using grep to find lines that each contain ALL search strings

This question specifically asks about grep, but really sed or awk are much cleaner for 'a AND b'-style matches, see How to run grep with multiple AND patterns?

This answer covers how to use grep to match all lines which match all inputs - my other answer covers matching any input.

Note that grep is more powerful than simple word-matching, it can match arbitrary patterns, including multiple words.

Consider the following simplified version of the example you provide:

$ cat file
{"id": 2796, "some_model": "Profile", "was_deleted": false}
{"id": 2797, "some_model": "Profile", "was_deleted": true}
{"id": 2798, "some_model": "Another", "was_deleted": false}

You could find item 2796 like so:

$ grep '"\?id"\? *: *2796 *,\?' file
{"id": 2796, "some_model": "Profile", "was_deleted": false}

Or find all non-deleted items:

$ grep '"\?was_deleted"\? *: *false *[,}]' file
{"id": 2796, "some_model": "Profile", "was_deleted": false}
{"id": 2798, "some_model": "Another", "was_deleted": false}

You can even combine the two, to only get item 2796 if it's not deleted (change false to true and the line no longer matches):

$ grep '"\?id"\? *: *2796 *,\?.*"\?was_deleted"\? *: *false *[,}]' file
{"id": 2796, "some_model": "Profile", "was_deleted": false}

Or roughly equivalent, using the grep-piping syntax you use above:

$ grep '"\?id"\? *: *2796 *,\?' file | grep '"\?was_deleted"\? *: *false *[,}]'
{"id": 2796, "some_model": "Profile", "was_deleted": false}

These examples hopefully look tricky to get right, because this is not a good idea!

The data you're working with looks to be JSON, a structured data format which grep is not well suited for processing. Valid JSON could be split across multiple lines or have fields in arbitrary order, which will break the above patterns. Not to mention arbitrary white-space (*), semi-optional quotes ("\?), and end of field vs. end of object markers ([,}]) which the above patterns should handle, but are easy to get wrong.

If you are trying to query JSON data, you need a JSON parser, which grep is not. http://www.json.org/ offers links to several popular JSON parsers in many languages, see if any of those will suite your needs. You will have much better success with a real tool than trying to construct complicated regular expressions.

Use grep to find lines containing a string, but not starting with another string

grep -i "session" php.ini | grep -vx ';.*'

Should work

-v is 'invert match', so only lines that don't match are displayed

-x is whole line match

How to find line followed by known string in bash

grep lets you print context along with matched line(s). Then you just need to ignore the matched line.

echo "$MyString" | grep -B1 String_I_know | head -1

How to grep for lines which contain particular words in a log file?

If you store your patterns in a file, one per line, you can use grep -f file-with-patterns file-to-search.log

From the man page:

   -f FILE, --file=FILE
Obtain patterns from FILE, one per line. The empty file
contains zero patterns, and therefore matches nothing. (-f is
specified by POSIX.)

Edit 2018:

Since I wrote this, I have become aware of the following interesting edge cases:

  • You can read the list of patterns from pipe using -f - (if you don't need stdin, i.e. you specified files on grep's command line) or -f <() (in any case)
  • grep's performance starts to fail badly if hundreds of patterns are passed. If your use case is that insane, consider generating and immediately executing a sed (or some other language) script, although this could potentially have problems with overlapping patterns.

How to use sed to find lines with a specific string and output to new file

Using sed

Observe that the following returns nothing:

$ sed -n '/[0-9]{2} install/p' file

But, this works:

$ sed -n '/[0-9]\{2\} install/p' file
2016-05-04 07:38:46 install libcairomm

The issue is that, in sed's default basic regular expressions, { and } are treated as ordinary characters. To make them special, they must be escaped with a backslash.

Alternatively, one can specify -E so that sed uses the more modern Extended Regular Expressions:

$ sed -En '/[0-9]{2} install/p' file
2016-05-04 07:38:46 install libcairomm

Saving to file

To save the output in a file, instead of displaying it in the terminal, add back the redirection > new.txt:

sed -n '/[0-9]\{2\} install/p' file > new.txt

Or:

sed -En '/[0-9]{2} install/p' file > new.txt

Compatibility

On very old versions of GNU sed, one cannot use -E. One must use -r instead:

sed -rn '/[0-9]{2} install/p' file > new.txt

Using grep

This task does not require sed's many advanced features. grep is sufficient:

$ grep -E '[0-9]{2} install' file
2016-05-04 07:38:46 install libcairomm

Or:

grep -E '[0-9]{2} install' file >new.txt

Find lines that contain certain text, and print what follows that text

You can just swap your grep with awk to get subset of line you're looking for:

tail -f /var/log/hive/hiveserver2.log |
awk -F "Parsing command: " '{print $2}'

SELECT * from table

-F "Parsing command: " makes "Parsing command: " field separator for awk command and $2 gives as substring after this marker.



Related Topics



Leave a reply



Submit