使用sed将字符串以“-”分隔符进行拆分不起作用。

3

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

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

不要使用 sed 解析 JSON。 - chepner
1
我认为字符串是YAML而不是JSON。我不认为Bash有任何内置功能可以让我解析这种类型的字符串。我想我必须将字符串按“-”分隔符拆分并存储在数组中,然后再使用“:”进一步拆分以获得最终结果,但我卡在了第一步。 - Lord OfTheRing
2个回答

2
您可以这样使用awk
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

查看在线演示

#!/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

我喜欢在awk中编写文件的最终行,但是我的外部变量fullfilepath无法被识别。我尝试使用printf a","n[i]","rtn[i]","rta[i] >> "$fullfilepath",但没有成功。我该如何将$fullfilepath传递给awk命令,以便它可以写入指定的文件? - Lord OfTheRing
@LordOfTheRing 你需要像这样将变量传递给awk:awk -v fullfilepath="$fullfilepath"... - Wiktor Stribiżew
我按照以下方式操作,但仍然无法运行:awk -v fullfilepath="$fullfilepath" '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++) { # 遍历找到的值并... printf a","n[i]","rtn[i]","rta[i] >> "$fullfilepath" # 输出到文件 } }' <<< "$string"
- Lord OfTheRing
谢谢,那个方法可行了,但是又出现了一个问题。我删除了最后一个字段,然后输出变成了这样:MAIN_ROLE,Name1 extra1,template1 extra2。 - Lord OfTheRing
@LordOfTheRing,没错,每种情况下字段只有两个,所以你需要将 rta[cnt]=$3 替换为 rta[cnt]=$2。请参见 此演示 - Wiktor Stribiżew
显示剩余5条评论

1

根据你提供的示例,你可以尝试以下 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. 

非常感谢您出色的逻辑和解释。我在awk命令方面几乎是文盲。 - Lord OfTheRing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接