【问题标题】:How to apply an awk command to a field defined by another awk command?如何将 awk 命令应用于另一个 awk 命令定义的字段?
【发布时间】:2022-01-31 16:01:02
【问题描述】:

我有 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", $9,$3,$2,$7,$7,$1}' 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]”的每个代码转换为&lt;AT&gt;标签,我可以使用下一个命令来管理:

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", $9,$3,$2,$7,$7,$1}' 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>

【问题讨论】:

    标签: bash shell awk


    【解决方案1】:

    一个想法使用GNU awk

    awk -F';' '
    { patsplit($3,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", $9,$3,$2
    
      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", $7,$1
    }
    ' 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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-28
      • 1970-01-01
      相关资源
      最近更新 更多