【问题标题】:Translating a sed one-liner into awk将 sed one-liner 翻译成 awk
【发布时间】:2017-06-12 04:03:08
【问题描述】:

我正在解析包含“key=value”对行的文件。一个例子可能是这样的:

Normal line
Another normal line
[PREFIX] 1=Something 5=SomethingElse 26=42
Normal line again

我想保留所有不包含 key=value 对的行,同时按如下方式转换所有包含 key=value 对的行:

Normal line
Another normal line
[PREFIX]
  AAA=Something
  EEE=SomethingElse
  ZZZ=42
Normal line again

假设我有一本有效的翻译词典。

我现在所做的是将输入传递给 sed,在那里我将空格转换为与 '^\[' 匹配的行的换行符。

然后将输出通过管道传输到这个 awk 脚本中:

BEGIN {
    dict[1] = "AAA"
    dict[5] = "EEE"
    dict[26] = "ZZZ"

    FS="="
}   
{
    if (match($0, "[0-9]+=.+")) {
        key = ""
        if ($1 in dict) {
            key = dict[$1]
        }
        printf("%7s = %s\n", key, $2)
    }   
    else {
        print
        next
    }   
}   

整个命令行就变成了:

cat input | sed '/^\(\[.*\)/s/ /\n/g' | awk -f script.awk

我的问题是:有什么办法可以在中间包含 sed 操作,从而摆脱额外的步骤?

【问题讨论】:

    标签: bash shell unix awk sed


    【解决方案1】:

    实际上我不能强制 awk 读取文件两次;一个用于 sed 命令,一个用于您的算法,所以我不得不修改您的算法。

    BEGIN {
        dict[1] = "AAA"
        dict[5] = "EEE"
        dict[26] = "ZZZ"
    
    #    FS="="
    }   
    $0 !~/[0-9]+=.+/ { print }
    /[0-9]+=.+/ {
       nb = split($0,arr1);
       for (i=1; i<=nb; i++ in arr1)  {
          nbb = split(arr1[i], keyVal, "=");
          if ( (nbb==2) && (keyVal[1] in dict) ) {
             printf("%7s = %s\n", dict[keyVal[1]], keyVal[2])
          } 
          else
             print arr1[i];
       }
    }   
    

    【讨论】:

      【解决方案2】:
      $ cat tst.awk
      BEGIN {
          split("1 AAA 5 EEE 26 ZZZ",tmp)
          for (i=1; i in tmp; i+=2) {
              dict[tmp[i]] = tmp[i+1]
          }
          FS="[ =]"
          OFS="="
      }
      $1 == "[PREFIX]" {
          print $1
          for (i=2; i<NF; i+=2) {
              print "  " ($i in dict ? dict[$i] : $i), $(i+1)
          }
          next
      }
      { print }
      
      $ awk -f tst.awk file
      Normal line
      Another normal line
      [PREFIX]
        AAA=Something
        EEE=SomethingElse
        ZZZ=42
      Normal line again
      

      【讨论】:

        【解决方案3】:

        当你必须转换很多时,你可以先将你的dict文件迁移到sed脚本文件中。当您的 dicht 文件具有固定格式时,您可以即时对其进行转换。

        假设你的 dict 文件看起来像

        1=AAA
        5=EEE
        26=ZZZ
        

        你的输入文件是

        Normal line
        Another normal line
        [PREFIX] 1=Something 5=SomethingElse 26=42
        Normal line again
        

        你想做类似的事情

        cat input | sed '/^\[/ s/ /\n/g' | sed 's/^1=/  AAA=/'
        # Or eliminating the extra step with cat
        sed '/^\[/ s/ /\n/g' input | sed 's/^1=/  AAA=/'
        

        所以下一步就是将 dict 文件转换为 sed 命令:

        sed 's#\([^=]*\)=\(.*\)#s/^\1=/   \2=/#' dictfile
        

        现在您可以将这些与

        sed '/^\[/ s/ /\n/g' input | sed -f <(
           sed 's#\([^=]*\)=\(.*\)#s/^\1=/   \2=/#' dictfile
        )
        

        【讨论】:

        • 有趣的替代解决方案。我仍然更喜欢@ed-morton 的“all-awk”解决方案,但很高兴看到它只在 sed 中的样子。
        猜你喜欢
        • 2014-05-08
        • 2014-03-19
        • 2012-09-01
        • 1970-01-01
        • 2012-11-02
        • 1970-01-01
        • 2011-06-01
        • 2015-02-04
        • 2012-07-20
        相关资源
        最近更新 更多