【问题标题】:Parsing the parsed column inside awk解析 awk 中的已解析列
【发布时间】:2018-04-13 22:30:42
【问题描述】:

我正在尝试使用 awk 来解析如下所示的文本文件:

001  data   John    Smith   address "London" | occupation "Driver" | exercise_level "Medium"
002  data   Rob Edward  address "Cardiff" | occupation "Physiotherapist" | exercise_level "High"
003  data   Dara    Pronk   address "Groningen" | country "Holland" | occupation "Teacher" | exercise_level "Low"
004  data   Marina  Francesca   address "Lugano" | country "Switzerland" | occupation "Chef" | exercise_level "High"

前 4 列由制表符分隔,第 5 列有一些元数据由管道分隔。

我想获取职业“key”的“values”作为我的第五列。我想要的输出将如下所示:

001  data   John    Smith   Driver
002  data   Rob Edward  Physiotherapist
003  data   Dara    Pronk   Teacher
004  data   Marina  Francesca   Chef

我可以通过这个命令得到职业:

awk -F'[\t|]' '{for(i=5;i<=NF;i++){if($i~/^ occupation/){c=$i}} print $1, $2, $3, $4, c}' my_file

但是,它将同时具有关键和价值(例如职业“物理治疗师”而不仅仅是物理治疗师)。有没有办法解析解析的列(即解析引号内的值),如下所示?

awk -F'[\t|]' '{for(i=5;i<=NF;i++){if($i~/^ occupation/){c=$i}} ((parse c here, take $2 of " delimiter)) print $1, $2, $3, $4, c}' my_file

【问题讨论】:

    标签: bash shell parsing unix awk


    【解决方案1】:

    使用 GNU awk

    $ awk '{match($0,/occupation "([^"]*)"/,arr);print $1,$2,$3,$4,arr[1]}' infile
    001 data John Smith Driver
    002 data Rob Edward Physiotherapist
    003 data Dara Pronk Teacher
    004 data Marina Francesca Chef
    

    其他 awk

    $ awk '{
             match($0,/occupation "([^"]*)"/); 
             s=substr($0,RSTART,RLENGTH); 
             gsub(/.* "|"/,"",s); 
             print $1,$2,$3,$4,s
    }' infile
    001 data John Smith Driver
    002 data Rob Edward Physiotherapist
    003 data Dara Pronk Teacher
    004 data Marina Francesca Chef
    

    输入:

    $ cat infile
    001  data   John    Smith   address "London" | occupation "Driver" | exercise_level "Medium"
    002  data   Rob Edward  address "Cardiff" | occupation "Physiotherapist" | exercise_level "High"
    003  data   Dara    Pronk   address "Groningen" | country "Holland" | occupation "Teacher" | exercise_level "Low"
    004  data   Marina  Francesca   address "Lugano" | country "Switzerland" | occupation "Chef" | exercise_level "High"
    

    --编辑地址评论--

    只是想知道,在第二个选项(其他 awk)中,是否有可能 存储其他变量(例如 var s 和 exercise_level 的职业 对于 var e)?

    根据您的需要修改变量search="....",您输入的顺序与您输入的结果相同

    awk -v search="occupation,exercise_level,address" '
    BEGIN{
        split(search, arr, /,/) 
    }
    {
        str = "";
        for(i=1; i in arr; i++)
        {
              regexp = arr[i]" \"([^\"]*)\"";
              if(match($0,regexp)){ 
                s=substr($0,RSTART,RLENGTH); 
                gsub(/.* "|"/,"",s);
                str = (str ? str OFS : "") s 
               }
         }
             print $1,$2,$3,$4,str
    }' infile
    

    【讨论】:

    • 这就是我要找的,非常感谢!!只是想知道,在第二个选项(其他 awk)中,是否可以存储其他变量(例如 var s 的占用和 var e 的 exercise_level)?
    • @kaka01 第二个选项,你必须一个一个地做,复制和粘贴,将occupation 更改为其他键和变量s 为其他,同样你在 gsub 中替换,否则你可以循环播放它
    • 嗨@3161993。谢谢!你能简单解释一下str = (str ? str OFS : "") s在这里是什么意思吗?
    • str = (str ? str OFS : "") s 是变量str 的串联,假设您有2 个或更多键要打印,那么循环str 的第一次迭代将为空,所以str = s,第二次迭代@987654333 @不为空所以str = str OFS s等等,上面一个可以写成if(str){ str = str OFS s } else { str = s }
    【解决方案2】:

    使用任何旧的 awk(GNU 也可以,但不是必需的):

    $ awk -F'\t' '{split($5,a,/ *\| */); for (i in a) { split(a[i],b," "); d[b[1]]=b[2] } print $1 OFS $2 OFS $3 OFS $4 OFS d["occupation"]}' i
    001 data John Smith "Driver"
    002 data Rob Edward "Physiotherapist"
    003 data Dara Pronk "Teacher"
    004 data Marina Francesca "Chef"
    

    拆分以便于阅读(和评论):

    BEGIN {
      OFS=FS='\t'           # set the input field separator
    } 
    
    {
      split($5,a,/ *\| */)  # split your embedded array by vertical bar
      for (i in a) {        # step through the array,
        split(a[i],b," ")   # splitting as you go
        #gsub(/"/,"",b[2])  # optionally remove quotes
        d[b[1]]=b[2]        # and assigning indices in a new data array
      }
      print $1 OFS $2 OFS $3 OFS $4 OFS d["occupation"]     # and print the result
    }
    

    虽然split()for 循环的额外步骤可能看起来很麻烦,但它的优点是可以在一个方便的数组中按名称 使用所有嵌入的数据。 (这解决了您在 cmets 中对 3161993 的回答提出的请求。)

    请注意,目前split() 会在空格处中断,因此如果您希望能够处理包含空格(即引号内)的数据,则需要做更多的工作。如果您希望输出不带引号,您可以在分配数据后gsub() 在 for 循环中(删除所有引号)或使用一对sub() 命令删除前导和尾随引号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-24
      • 2014-01-01
      • 2017-04-07
      • 1970-01-01
      • 2016-05-04
      • 2017-07-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多