Bash try to count number of occurence?

Viewed 104

I've this type of data :

Folder : 1
Folder : 2
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
Folder : 3
  VM: XXX
  VM: XXX
Folder : 4
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
Folder : 5
Folder : 6
etc ...

I'm able to retrieve the total of VM in this file :

cat my_file | grep VM | wc -l
19

But I would like to lean how can I have this output :

Folder : 1
Total VM : 0

Folder : 2
Total VM : 12

Folder : 3
Total VM : 2

Folder : 4
Total VM : 5

Folder : 5
Total VM : 0

Folder : 6
Total VM : 0
etc ...

I don't know how to retrieve the number of VM in each Folder with bash...

Someone to explain to me how to do that ?

3 Answers

With your shown samples could you please try following, written and tested in GNU awk.

awk '
/^Folder/{
  if(prevFolder){
    print prevFolder ORS "Total VM : " (vmVal?vmVal:0)
  }
  vmVal=""
  prevFolder=$0
  next
}
NF{
  vmVal++
}
END{
  if(prevFolder){
    print prevFolder ORS "Total VM : " (vmVal?vmVal:0)
  }
}
'  Input_file


2nd solution: OR with function approach try following:

awk '
function checkVal(value){
  if(value){
    print value ORS "Total VM : " (vmVal?vmVal:0)
  }
}
/^Folder/{
  checkVal(prevFolder)
  vmVal=""
  prevFolder=$0
  next
}
NF{
  vmVal++
}
END{
  checkVal(prevFolder)
}
' Input_file

Explanation: Adding detailed level explanation for above code.

awk '                       ##Starting awk program from here.
function checkVal(value){   ##Creating function named checkVal by passing value variable in it.
  if(value){                ##Checking if value is NOT NULL then do following.
    print value ORS "Total VM : " (vmVal?vmVal:0)
                            ##Printing value ORS Total VM : and vmVal value or 0 if its NULL.
  }
}
/^Folder/{                  ##Checking condition if line starts from Folder then do following.
  checkVal(prevFolder)      ##Calling checkVal function with passing prevFolder value to it.
  vmVal=""                  ##Nullifying vmVal here.
  prevFolder=$0             ##Setting preFolder to current line here.
  next                      ##next will skip all further statements from here.
}
NF{                         ##Checking condition if NF is NOT NULL then do following.
  vmVal++                   ##Increment vmVal with 1 here.
}
END{                        ##Starting END block of this program from here.
  checkVal(prevFolder)      ##Calling checkVal function with prevFolder value here.
}
' Input_file                ##Mentioning Input_file name here.

A simplified gnu-awk using custom RS:

awk -v RS='Folder *:[^\n]+' 'hdr {print hdr; print "Total VM : " gsub(/[[:space:]]*VM:/, "&") ORS} {hdr=RT}' file

Folder : 1
Total VM : 0

Folder : 2
Total VM : 12

Folder : 3
Total VM : 2

Folder : 4
Total VM : 5

Folder : 5
Total VM : 0

Folder : 6
Total VM : 0

A more readable version:

# we use RS with regex as /Folder :<rest of the line?/
# RT gives as value of matched text
awk -v RS='Folder *:[^\n]+' '
hdr {
   print hdr   # print header line
   # in gsub we match 0+ white space folowed by VM:
   # dummy gsub replace match with itself but it returns no of matches
   print "Total VM : " gsub(/[[:space:]]*VM:/, "&") ORS
}
{
   hdr = RT    # store value of RT in variable hdr
}' file

Using GNU awk:

awk '/Folder/ { folder=$3;map[folder]=0;next } /VM:/ { map[folder]++ } END { PROCINFO["sorted_in"]="@ind_num_asc";for (i in map) { printf "Folder : %s\nTotal VM : %s\n\n",i,map[i] } }' file

Explanation:

awk '/Folder/ {                                                   # Process lines starting with "Folder"
                folder=$3;                                        # Set variable folder to the third space delimited field
                map[folder]=0;                                    # Initialise an array map with the folder as the index and 0 as the value.
                next 
              } 
        /VM:/ {                                                   # Process lines with VM
                map[folder]++                                     # Increment the array for the folder
              } 
          END { 
                PROCINFO["sorted_in"]="@ind_num_asc";             '# Set array ordering
                for (i in map) { 
                   printf "Folder : %s\nTotal VM : %s\n\n",i,map[i]      # Loop through the array and print the data in the format required.
                } 
              }' file
Related