16

I'd like to search for text that may be split over several lines in a file. A grep that would ignore line breaks and return the matching span of lines.

e.g. I would be searching for is an example file, and expect it to be found in the following file:

This is
an
example file.

Not to depend on leading or trailing spaces, entirely ignoring all forms of white space might be best (ideally, treating any sequence of white space as a single space).


One non-ideal solution is tr '\n' ' ' | grep, that discriminates between matches and non-matches, but doesn't show the match, nor deals well with big files.

4
  • on SO (no definitive answer) : stackoverflow.com/q/1858312/1449460 May 18, 2015 at 17:26
  • As a side note, emacs' search seems to do the job (isearch-forward) May 18, 2015 at 17:33
  • So does Vim's: /This\_sis. For more details: :help \_s.
    – lcd047
    May 18, 2015 at 17:37
  • Add this line at the end of your search line: tr -n "\n" This will remove all new lines. Hope this help!
    – Dan Howel
    Aug 18, 2017 at 18:28

2 Answers 2

15

The GNU grep can do it

grep -z 'is\san\sexample\sfile.' file

To fulfill some points which arise in comments there are some modifications to script:

 grep -oz '^[^\n]*\bis\s*an\s*example\s*file\.[^\n]*' file

Regarding huge files I have no imagination of memory limitation but in the case of problem you are free to use sed

sed '/\bis\b/{
          :1
          N
          /file\.\|\(\n.*\)\{3\}/!b1
         }
     /\<is\s*an\s*example\s*file\./p
     D' file

that keep no more than 4-lines (because 4 words in pattern) in memory (\(\n.*\)\{3\}).

5
  • 6
    As I’m sure you know, the -z option tells grep to treat newlines as ordinary text characters, and look for nul bytes to separate records.  In a text file with no nul bytes (i.e., the typical case), grep -z will treat the entire file as one line.  So (1) this raises the question of how well it can handle large files, and (2) if it finds a match, it will write out the entire file, giving no clue as to the location of the match.  Also (3) the OP said, “ideally, treating any sequence of white space as a single space,” so you should use \s+ and add -E. May 18, 2015 at 23:38
  • 1
    @G-Man Thank you for comment. Please see edited answer.
    – Costas
    May 19, 2015 at 9:28
  • 1
    (0) Ah, -o; I keep forgetting about that.  Clever way to use it.  (1) Your new grep answer begins ^[\n]*; that’s a typo for [^\n]*.  (2) I said \s+ deliberately.  be\s*little will match belittle, and care\s*less will match careless.  But I guess that’s a minor problem.  And, if you don’t want to use -E, you can use “the poor man’s version” of \s+, namely, \s\s*.  (3) Nice sed command.  It can fail if there are blank lines (so the four-word phrase can spread over more than four lines); I was able to fix that by adding s/\n\s*\n/\n/. May 20, 2015 at 1:10
  • @G-Man Thank you againg. Your comments are very useful. I have try to post more or less portable code because famous members everytime push me to do so. Anyway even without -E you steel able to use + in \s\+ form. Empty lines inside of pattern seems to be a contrived.
    – Costas
    May 20, 2015 at 8:55
  • I was thinking of paginated text documents, like RFCs — ISTR that man pages look like that on some systems (or did) — but, on further thought, it occurs to me that most such documents have page header(s) and/or footer(s) that would need to be stripped out before you could hope to grep them for phrases. May 20, 2015 at 16:44
7

Try this:

pcregrep -M '\bThis\s+is\b' <<EOT
This
is
an example
file.
EOT
4
  • Do I have to type \s 5 times if I search for "this is a very long pattern" ? May 18, 2015 at 17:31
  • 1
    Yes: the point is \s matches spaces, and newline is a "space".
    – lcd047
    May 18, 2015 at 17:32
  • I mean, what if the file is This\nis a very\nlong pattern, and I don't know where the line breaks might occur. I'd have to search for This\sis\sa\svery\slong\spattern, right ? (which becomes tedious as the length of the pattern increases or is pasted from elsewhere) May 18, 2015 at 17:36
  • 2
    Then you do it like this: pcregrep -M "$( echo 'This is a very long pattern' | sed 's/ /\\s+/g' )" file.
    – lcd047
    May 18, 2015 at 17:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .