1

This question already has an answer here:

I've been looking to extract a block of text, from a text file, containing a string with no success. Any help would be really appreciated.

For example: I have a file named xyz with below contents:

10:10:10 ::  blah blah blah
10:10:10 ::  blah blah blah
10:10:11 ::  $VAR1 = {
10:10:11 ::     'Id' = 'A0001'
10:10:11 ::     'Name' => 'Smith'
10:10:12 ::     'Age' => '21'
10:10:12 ::  };
10:10:12 ::  blah blah blah
10:10:12 ::  blah blah blah
10:10:14 ::  $VAR1 = {
10:10:14 ::     'Id' = 'A0002'
10:10:15 ::     'Name' => 'Jane'
10:10:15 ::     'Age' => '18'
10:10:15 ::  };
10:10:15 ::  blah blah blah
10:10:16 ::  blah blah blah
10:10:16 ::  $VAR1 = {
10:10:16 ::     'Id' = 'A0003'
10:10:16 ::     'Name' => 'Adams'
10:10:16 ::     'Age' => '25'
10:10:16 ::  };

and I want to extract a block of text between $VAR1 and }; containing a A0002. so the result of sed/grep/awk is below:

10:10:14 ::  $VAR1 = {
10:10:14 ::     'Id' = 'A0002'
10:10:15 ::     'Name' => 'Jane'
10:10:15 ::     'Age' => '18'
10:10:15 ::  };

So far I've managed to extract all blocks of text between $VAR1 and };, using below:

sed -n "/VAR1/,/};/p" xyx

which returns the following. Is there a way to filter containing text A0002:

10:10:11 ::  $VAR1 = {
10:10:11 ::     'Id' = 'A0001'
10:10:11 ::     'Name' => 'Smith'
10:10:12 ::     'Age' => '21'
10:10:12 ::  };
10:10:14 ::  $VAR1 = {
10:10:14 ::     'Id' = 'A0002'
10:10:15 ::     'Name' => 'Jane'
10:10:15 ::     'Age' => '18'
10:10:15 ::  };
10:10:16 ::  $VAR1 = {
10:10:16 ::     'Id' = 'A0003'
10:10:16 ::     'Name' => 'Adams'
10:10:16 ::     'Age' => '25'
10:10:16 ::  };

marked as duplicate by don_crissti, cuonglm, Costas, Gilles, Archemar Sep 28 '15 at 11:23

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.

  • Thanks @don_crissti for the quick answer, Your solution works on the sample file! but the production file I have, has the timestamps on each line, Please could you take a look at the updated question and advise a solution. I really appreciate your help! Thanks – Narayan Akhade Sep 28 '15 at 11:34
  • Tried, but no luck. comes back with nothing :( – Narayan Akhade Sep 28 '15 at 12:41
  • Thanks Don. I've managed to get it work using - sed 'H;/{$/h;/\;$/x;/{\n.*A0002/!d' xyz, but it doesn't work with my production file that is quite large. There I am getting "Hold space overflowed." error message. Looking at the sed man pages, it appears there is limit to 4000 characters only to hold space. Any chance, you know how could I resolve this? Thanks – Narayan Akhade Sep 28 '15 at 13:15
  • With a two-pass, first grep the line numbers for range start, pattern and range end, process the output into something like 23,145p and pass that to a second sed -nf -. Example: grep -n '{$\|A0002\|};$' infile | sed '$!N;/\n.*A0002/{N;s/^\([0-9]\{1,\}\):.*\n.*\n\([0-9]\{1,\}\):.*/\1,\2p/p;d};D' | sed -n -f - infile (replace infile with your file name). – don_crissti Sep 28 '15 at 13:51
  • I am using SunOS... not sure how to check sed version. what is the first grep in above comment. It doesn't return anything fro me. – Narayan Akhade Sep 28 '15 at 14:30
0

Change the input into a record per line and grep, like:

cat input.txt | tr '\n' ' ' | tr ';' '\n' | egrep A0002

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