如何将 awk 命令应用于由另一个 awk 命令定义的字段?

How to apply an awk command to a field defined by another awk command?

我有 2 个任务要对由字段分隔的数据字符串执行,我可以分别为每个任务提出一个 awk 命令,但我需要的是将第二个任务应用于第三个字段,并让第一项任务结果中的第二项任务结果。

文件中的数据data.csv

31;Area A;Language B1 G1-T1-(3343-1-25274)+(3343-1-25278)+(3345-1-25676);German;;;0;;Wolfgang Mozart

第一个任务是生成一个 xml 结构,这是通过下一个 awk 命令完成的:

awk -F';' -v OFS=';' '{printf "<A>\n\t<T>%s</T>\n\t<S>%s</S>\n\t<AT>%s</AT>\n\t<D>%s</D>\n\t<Id>%s</Id>\n</A>\n", ,,,,,}' test.csv

结果是:

<A>
    <T>Wolfgang Mozart</T>
    <S>Language B1 G1-T1-(3343-1-25274)+(3343-1-25278)+(3345-1-25676)</S>
    <AT>Area A</AT>
    <D>0</D>
    <Id>31</Id>
</A>

第二个任务是将格式为“[0-9]{4}-[1-5]”的每个代码转换为 <AT> 标签,我可以使用下一个命令来管理它:

awk 'BEGIN{FPAT="[0-9]{4}-[1-5]"} {for (i=1; i <= NF; i++) print "<AT>"$i"</AT>"}' test.csv

结果是(顺便说一句,我无法完成重复时只打印出一个实例):

<AT>3343-1</AT>
<AT>3343-1</AT>
<AT>3345-1</AT>

期望的输出是:

<A>
    <T>Wolfgang Mozart</T>
    <S>Language B1 G1-T1-(3343-1-25274)+(3343-1-25278)+(3345-1-25676)</S>
    <AT>Area A</AT>
    <AT>3343-1</AT>
    <AT>3345-1</AT>
    <D>0</D>
    <Id>31</Id>
</A>

我能想到的最好的命令是下一个,它没有产生所需的输出:

awk -F';' -v OFS=';' 'BEGIN{FPAT="[0-9]{4}-[1-5]"} {for (i=1; i <= NF; i++) printf "<A>\n\t<T>%s</T>\n\t<S>%s</S>\n\t<AT>%s</AT>\n\t<D>%s</D>\n\t<Id>%s</Id>\n</A>\n", ,,,,,}' test.csv

结果是:

<A>
    <T>Wolfgang Mozart</T>
    <S>Language B1 G1-T1-(3343-1-25274)+(3343-1-25278)+(3345-1-25676)</S>
    <AT>Area A</AT>
    <AT>3343-1</AT>
    <D>0</D>
    <Id>31</Id>
</A>
<A>
    <T>Wolfgang Mozart</T>
    <S>Language B1 G1-T1-(3343-1-25274)+(3343-1-25278)+(3345-1-25676)</S>
    <AT>Area A</AT>
    <AT>3343-1</AT>
    <D>0</D>
    <Id>31</Id>
</A>
<A>
    <T>Wolfgang Mozart</T>
    <S>Language B1 G1-T1-(3343-1-25274)+(3343-1-25278)+(3345-1-25676)</S>
    <AT>Area A</AT>
    <AT>3345-1</AT>
    <D>0</D>
    <Id>31</Id>
</A>

一个想法使用 GNU awk:

awk -F';' '
{ patsplit(,arr,"[0-9]{4}-[1-5]")          # split field #3 into NNNN-N strings
  delete seen                                # clear seen[] array
  for (i in arr)                             # for each NNNN-N string in arr[], store as index in 
      seen[arr[i]]                           # seen[] array; duplicates are effectively eliminated

  printf "<A>\n\t<T>%s</T>\n\t<S>%s</S>\n\t<AT>%s</AT>\n", ,,

  PROCINFO["sorted_in"]="@ind_str_asc"       # assuming we want NNNN-N strings displayed in sorted order 

  for (at in seen)
      printf "\t<AT>%s</AT>\n", at

  printf "\t<D>%s</D>\n\t<Id>%s</Id>\n</A>\n", ,
}
' data.csv

这会生成:

<A>
        <T>Wolfgang Mozart</T>
        <S>Language B1 G1-T1-(3343-1-25274)+(3343-1-25278)+(3345-1-25676)</S>
        <AT>Area A</AT>
        <AT>3343-1</AT>
        <AT>3345-1</AT>
        <D>0</D>
        <Id>31</Id>
</A>