6

This question already has an answer here:

I am on Ubuntu 16.04 and I want to search files for let’s say “if” and I want to the output until “endif”. The file could look like this

if …
  SOME CODE
endif

I can do this with grep -A9 if my_file | grep -B9 endif. This doesn’t works if the “if” clause is larger than 9 and if several “if” clauses are in the same file and if the first grep command contains several “if” clauses. The option -m1 in the second grep doesn’t help. Nested “if” clauses can be ignored. Has somebody an idea, maybe not with grep?

Difference to How do I grep for multiple patterns on multiple lines?

  1. The question asks for a solution with grep which is answered already in the question: grep -A9 if my_file | grep -B9 endif. The solution doesn’t work in my case but would work in the case of the other question.

  2. The proposed grep solutions of the other question don’t work (with Ubuntu?): grep: ein nicht geschütztes ^ oder $ wird mit -Pz nicht unterstützt. which is something like grep: a not protected ^ or $ is not supported with -Pz. I use the following:

    root:/tmp# cat file
    Some text
    begin
    Some text goes here.  
    end
    Some more text 
    root:/tmp# grep -Pzo "^begin\$(.|\n)*^end$" file
    grep: ein nicht geschütztes ^ oder $ wird mit -Pz nicht unterstützt
    
  3. The proposed solutions search only for pattern which start at the beginning of the line if I interpret the proposed solution correctly. Even if I remove ^ the command doen't work.

marked as duplicate by αғsнιη, WinEunuuchs2Unix, David Foerster, heemayl command-line Nov 14 '16 at 3:46

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • About 2: Show us what pattern you used with grep -Pz. 3. What is a "pure Linux solution"? 4. grep can look anywhere in the line. – muru Nov 14 '16 at 1:57
  • 2) You can edit your post, as you very well know. 3) LOL, Perl is not a secondary package by a long shot. It's as likely to be present on any Linux system as grep or sed. 4) So you know what ^ does. – muru Nov 15 '16 at 1:13
  • 2) The trick was to put 8 (!) blanks in front because it is inside of a numbering. 3) I refer to the pcregrep and so on of the answer of steeldriver. But it is a matter of tasked, as I said. Anyway I have taken it out. 3) Yes, but even without ^ it doesn’t work. – musbach Nov 15 '16 at 7:59
  • The title doesn't fit the question: it should be Show lines between two patterns. Whoever wants lines from the first line on, doesn't get his answer here – Bilow Dec 12 '18 at 13:08
18

You can use sed for that:

sed -n '/if/,/endif/p' myfile
  • -n don't print anything until we ask for it
  • /if/ find the first line with this
  • , keep going until...
  • /endif/ this is the last line we want
  • p print the matched lines
  • I get the following error sed: -e Ausdruck #1, Zeichen 12: Fehlender Befehl is something like sed: -e expression #1, character 12: missing command. You explain the p but it is missing in the command. – musbach Nov 13 '16 at 17:13
  • oops haha there it is @musbach edited – Zanna Nov 13 '16 at 17:17
  • @musbach more than welcome :D – Zanna Nov 13 '16 at 17:23
  • 1
    Indeed, sed or (better!) awk are precisely the tools for this, as standard programs that have built-in begin/end pattern matching. – underscore_d Nov 13 '16 at 19:54
6

Traditional grep is line-oriented. To do multiline matches, you either need to fool it into slurping the whole file by telling it that your input is null terminated e.g.

grep -zPo '(?s)\nif.*\nendif' file

or use a more flexible tool such as pcregrep

pcregrep -M '(?s)\nif.*?\nendif' file

or perl itself

perl -00 -ne 'print if m/^if.*?endif/s' file

Alternatively, for matching structured input in a grep-like way, there's sgrep

sgrep '"if" .. ("endif") containing "SOME CODE"' file
  • 2
    AFAIK, trying to fool grep et al. by specifying a nonexistent (or even just very rare) terminator is inherently brittle and non-portable, due to limited line buffer sizes in various implementations. IIRC one does not need to worry much if using the GNU versions, but not everyone does that. Anyway, it seems to me that sed or awk are far better suited to this sort of task than non-standard extended greps or perl: both seem too complex for a simple "sed 101" question like this, and extended greps are probably equally non-portable. – underscore_d Nov 13 '16 at 19:50
  • @underscore_d this site is about Ubuntu, so portability isn't really an issue. And learning more about what grep, or any other tool, can do is always a good thing (even if just for fun) isn't it? – Zanna Nov 13 '16 at 20:19
  • @Zanna I didn't even notice this was Ask Ubuntu... all of SE blurs together some days. :D But it's not unreasonable to suppose that enough people who happen to use Ubuntu might be interested in writing portable shell. And sure, don't get me wrong, I think this answer is useful by showing how this could be done with some forms of grep, but just wanted to note some (if theoretical) limitations and alternatives. – underscore_d Nov 13 '16 at 23:12
4

A solution awk could look like: awk '/if/,/endif/' file

Of course, it is similar to the solution with sed.

  • 4
    Yes, this works as well. One difference is between the sed and awk solution: If I replace file by * I get different results. sed seems to search only for ascii files(?) and awk includes binary files as well. – musbach Nov 14 '16 at 7:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.