使用 sed 无法使用“-”定界符拆分字符串

splitting string with "- " delimiter using sed not working

我有以下字符串,每行由换行分隔作为输入字符串

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

我喜欢将 YAML 字符串打印成逗号分隔的字符串,如下所示。输入字符串可以在“-”之后有任意数量的组件,这会产生新记录,但 MAIN_ROLE 值保持不变,第一列:

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

我尝试用下面的代码用“-”拆分行,但我没有得到正确的结果

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

您可以这样使用awk

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

参见 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=;cnt=0            # Set a (main name) and cnt (counter) vars
}
/^-/{                     # When line starts with -
    rta[cnt]=; getline; # Add role template app ID to rta array, read next line
    rtn[cnt]=; getline; # Add role template name to rtn array, read next line
    n[cnt]=;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

根据您展示的示例,您可以尝试遵循 awk 程序。这可以在很少的条件下简单地完成,而不是使用阵列系统。

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

说明: 为以上添加详细说明。

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.