0

Edited the question to try and make things clearer
I have a file that looks like this:

BEGIN  
Block name : Block1
Var names : var1 var2 var3  
var1 32.7
var2 12.2
var3 65.4
END  
BEGIN 
Block name : Block43
Var names : bar55 foo3  
bar55 654.555
foo3 23.4
END 
BEGIN 
Block name : Block66
Var names : bar2  
bar2 33.0987
END 

The final output should be:

Block1 has a var named var1 and its value is 32.7 
Block1 has a var named var2 and its value is 12.2
Block1 has a var named var3 and its value is 65.4
Block43 has a var named bar55 and its value is 654.555
Block43 has a var named foo3 and its value is 23.4
Block66 has a var named var1 and its value is 33.0987   

I do not know the size of the block or how many vars it has.
I do know for certain that each block is surrounded by a BEGIN and END lines.

Is there a way to parse the file to individual blocks and loop through them?
Something in the lines of :

for block in file; do
    block_name=$(echo $block | grep 'Block' | cut -d ":" -f2)
    vars=$(echo $block | grep 'Var' | cut -d ":" -f2)
for var in $vars;do
   var_value=$(echo $block | grep '^$var')
   echo "$block_name has a var named $var and its value is $var_value"
done

done

The closest answer to my question was using either sed or awk to get the first instance of a block and then quitting.
I am looking to get information from every block that is surrounded by BEGIN and END.

Thanks for your help.

  • What kind of variable? A shell variable or an awk variable? What do you want to do with this variable? – terdon Jan 27 '21 at 11:58
  • I wanted to iterate over each pattern and then use the lines inside the block. for example i would like to get the number attached to foo and bar – user280009 Jan 27 '21 at 12:02
  • That is a very different question. Please [edit] your question and ask what you need. Tell us what the final objective is, and ask about that. There is no need to store things in a variable for what you describe. Just show us your desired output and we can give you a solution. – terdon Jan 27 '21 at 12:05
  • 1
    As of now, the BEGIN/END lines don't make any difference, awk '/foo/{print $2}' file would work as well as grep 'foo' file | cut -d " " -f2. Can you explain (or create a better example) where these won't work and why you need to iterate over the lines between BEGIN and END? – pLumo Jan 27 '21 at 12:21
  • 1
    Read https://stackoverflow.com/questions/65621325/how-do-i-find-the-text-that-matches-a-pattern then replace the ambiguous word "pattern" with a combination of "string" or "regexp" and "full" or "partial", whichever you mean in each context, everywhere it occurs in your question so we can best help you. Make sure your sample input/output contains regexp metachars and potential partial matches such that it demonstrates your requirements in those areas. – Ed Morton Jan 27 '21 at 12:28
  • Does your file actually contain the ***? – terdon Jan 27 '21 at 12:35
  • no each block starts with something else i used the asterisk for a dummy example – user280009 Jan 27 '21 at 12:40
  • 2
    Please make sure your file accurately represents your real data. The specific values are important here. For example, matching an asterisk requires some special handling (you would need to escape it), so we need to see exactly what your file looks like. – terdon Jan 27 '21 at 12:59
  • Duly noted .The next question ill post will be more informative – user280009 Jan 27 '21 at 13:02
  • It's not too late to improve this question so we can help you. – Ed Morton Jan 28 '21 at 01:54
  • 1
    I edited my question to better explain the problem I am facing. I hope the changes made things clearer . @EdMorton – user280009 Jan 28 '21 at 07:53

2 Answers2

1

Here's one way:

$ awk '/^Block/{block=$1}
       /foo/{
          printf "The value of foo in %s is : %s\n",block,$2
       }' file
The value of foo in Block1 is : 5423
The value of foo in Block2 is : 6435907
The value of foo in Block3 is : 353321111
The value of foo in Block4 is : 9876543210

Or, if you can have multiple lines starting with Block and you only want the one right after BEGIN, you can use:

awk '/BEGIN/{a=1}
     /END/{a=0} 
     /^Block/ && a{
        block=$1; 
        a=0
     } 
     /foo/{
       printf "The value of foo in %s is : %s\n",block,$2
     }' file 
terdon
  • 242,166
  • what if I have more than one foo value? lets say Block1 has 5 different foo values and a bar value i would like to print too – user280009 Jan 27 '21 at 12:53
  • 2
    @user280009 please make sure that your question actually asks everything you need. We can't guess what your requirements are. How can we know what values you need? – terdon Jan 27 '21 at 12:57
1
$ cat tst.awk
/^Block name/ { name = $NF }
/END/ {
    for (var in var2val) {
        printf "%s has a var named %s and its value is %s\n", name, var, var2val[var]
    }
    delete var2val
}
NF==2 { var2val[$1] = $2 }

$ awk -f tst.awk file
Block1 has a var named var1 and its value is 32.7
Block1 has a var named var2 and its value is 12.2
Block1 has a var named var3 and its value is 65.4
Block43 has a var named foo3 and its value is 23.4
Block43 has a var named bar55 and its value is 654.555
Block66 has a var named bar2 and its value is 33.0987
Ed Morton
  • 31,617