splitting string with "- " delimiter using sed not working

Viewed 370

I have below string, each line delimited by New Line as Input string

string="name: MAIN_ROLE
description: ROLE DESCRIPTION
readOnly: 
roleReferences:
- roleTemplateAppId: app1
  roleTemplateName: template2
  name: Name1
- roleTemplateAppId: app2
  roleTemplateName: template2
  name: Name2
"

I like to print YAML string into comma delimited string as below result. Input string could have any number of component after "-" which makes new record but MAIN_ROLE value remain the same first column:

MAIN_ROLE,Name1,template1,app1
MAIN_ROLE,Name2,template2,app2

I tried below code to split the line with "- " but I am not getting correct result

echo "$a" | sed -n $'/^- $/,/^- $/p' <<< $string
2 Answers

You can use awk this way:

awk 'NR==1{a=$2;cnt=0} /^-/{rta[cnt]=$3;getline;rtn[cnt]=$2; getline; n[cnt]=$2;cnt++} END{ for(i=0;i<cnt;i++) { print a","n[i]","rtn[i]","rta[i] } }' file > outputfile

See the online demo:

#!/bin/bash
string="name: MAIN_ROLE
description: ROLE DESCRIPTION
readOnly:
roleReferences:
- roleTemplateAppId: app1
  roleTemplateName: template1
  name: Name1
- roleTemplateAppId: app2
  roleTemplateName: template2
  name: Name2
"
awk 'NR==1{               # When on Line 1
    a=$2;cnt=0            # Set a (main name) and cnt (counter) vars
}
/^-/{                     # When line starts with -
    rta[cnt]=$3; getline; # Add role template app ID to rta array, read next line
    rtn[cnt]=$2; getline; # Add role template name to rtn array, read next line
    n[cnt]=$2;cnt++       # Add name to n array, increment the cnt variable
}
END{                      # When the file processing is over
    for(i=0;i<cnt;i++) {  # Iterate over the found values and... 
        print a","n[i]","rtn[i]","rta[i]  # print them
    }
}' <<< "$string"

# => MAIN_ROLE,Name1,template1,app1
#    MAIN_ROLE,Name2,template2,app2

With your shown samples, you could try following awk program. This could be simply done with few conditions rather than using array systems.

awk '
BEGIN{ OFS="," }
/roleTemplateAppId/{
  if(name && template){
    print "MAIN_ROLE",name,template,$NF
  }
  name=template=""
}
/roleTemplateName:/{
  template=$NF
  next
}
/name:/{
  name=$NF
}
END{
  if(name && template){
     print "MAIN_ROLE",name,template,$NF
  }
}
'  Input_file

Explanation: Adding detailed explanation for above.

awk '                                     ##Starting awk program from here.
BEGIN{ OFS="," }                          ##Setting OFS to , in BEGIN section.
/roleTemplateAppId/{                      ##Check if line contains roleTemplateAppId then do following.
  if(name && template){                   ##check if name and template is SET then do following.
    print "MAIN_ROLE",name,template,$NF   ##Printing MAINE_ROLE name, template and last field value here.
  }
  name=template=""                        ##Nullifying name and template here.
}
/roleTemplateName:/{                      ##Check if roleTemplateName: is found in current line then do following.
  template=$NF                            ##Setting template to last field of current line.
  next                                    ##next will skip all further statements from here.
}
/name:/{                                  ##Checking condition if line contains name: then do following.
  name=$NF                                ##Setting name value as last field name.
}
END{                                      ##Starting END block of this program from here.
  if(name && template){                   ##check if name and template is SET then do following.
     print "MAIN_ROLE",name,template,$NF  ##Printing MAINE_ROLE name, template and last field value here.
  }
}
'  Input_file                             ##Mentioning Input_file name here. 
Related