【问题标题】:Can I delete a field in awk?我可以删除awk中的字段吗?
【发布时间】:2021-03-24 19:01:42
【问题描述】:

这是test.txt

0x01,0xDF,0x93,0x65,0xF8
0x01,0xB0,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0xB2,0x00,0x76

如果我跑 awk -F, 'BEGIN{OFS=","}{$2="";print $0}' test.txt 结果是:

0x01,,0x93,0x65,0xF8
0x01,,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,,0x00,0x76

$2 没有被删除,它只是变成了空的。 我希望,在打印 $0 时,结果是:

0x01,0x93,0x65,0xF8
0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0x00,0x76

【问题讨论】:

    标签: awk sed cut


    【解决方案1】:

    我相信最简单的方法是使用 sub 函数将第一次出现的连续 ,,(在您将第二个字段设为 NULL 后创建)替换为单个 ,。但这假设您在字段值之间没有任何逗号。

    awk 'BEGIN{FS=OFS=","}{$2="";sub(/,,/,",");print $0}' Input_file
    

    第二个解决方案: 或者您可以使用match 函数来捕获从第一个逗号到下一个逗号出现的正则表达式,并获取匹配字符串的前后行。

    awk '
    match($0,/,[^,]*,/){
      print substr($0,1,RSTART-1)","substr($0,RSTART+RLENGTH)
    }' Input_file
    

    【讨论】:

      【解决方案2】:

      这有点笨拙,但这会将字段 2 之后的每个字段向下移动一个位置,然后更改 NF,因此不需要的字段不存在:

      $ awk -F, -v OFS=, '{ for (i = 2; i < NF; i++) $i = $(i+1); NF--; print }' test.txt
      0x01,0x93,0x65,0xF8
      0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01
      0x01,0x00,0x76
      $
      

      使用 GNU Awk 4.1.3 和 BSD Awk 测试(macOS Mojave 10.14.6 上的“awk version 20070501”——别问;这也让我感到沮丧,但有时雇主并不擅长前瞻性思考)。设置 NF 可能会或可能不会在旧版本的 Awk 上工作 - 我有点惊讶它确实工作,但惊喜是一个令人愉快的改变。

      【讨论】:

        【解决方案3】:

        如果 Awk 不是绝对要求,并且输入确实与您的示例一样微不足道,sed 可能是一个更简单的解决方案。

        sed 's/,[^,]*//' test.txt
        

        如果您想删除第二个字段,这尤其优雅。一种更通用的删除方法,第 n 个字段将要求您输入一个匹配第一个 n - 1 的正则表达式,然后是 nth,然后用第一个 n - 1 替换它。

        所以对于 n = 4 你会有

        sed 's/\([^,]*,[^,]*,[^,]*,\)[^,]*,/\1/' test.txt
        

        或者更一般地说,如果您的 sed 方言理解用于指定重复的大括号

        sed 's/\(\([^,]*,\)\{3\}\)[^,]*,/\1/' test.txt
        

        一些sed 方言允许您使用-r-E 之类的选项来消除所有那些讨厌的反斜杠,但同样,这不是普遍支持或可移植的。

        如果不明显,[^,] 匹配一个不是(换行符或)逗号的单个字符; \1 从第一个括号匹配中调用文本(反向引用;\2 调用第二个,等等)。

        此外,这完全不适合转义或引用的字段(尽管我并不是说不能这样做)。无论如何,每个逗号都充当字段分隔符。

        【讨论】:

        • \n 不是完全可移植的,但是是的。
        【解决方案4】:

        尽管这实际上是为cut量身定制的工作,但所有现有的解决方案都很好:

        cut -d, -f 1,3- file
        
        0x01,0x93,0x65,0xF8
        0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
        0x01,0x00,0x76
        

        如果要删除第三个字段,请使用:

        cut -d, -f 1,2,4- file
        

        要删除第 4 个字段使用:

        cut -d, -f 1-3,5- file
        

        【讨论】:

        • 以下对于删除第二个字段更好,尤其是当字段很多时:cut --complement -d, -f2 file
        【解决方案5】:

        使用 sub() 函数评论the first solution of @RavinderSingh13

        awk 'BEGIN{FS=OFS=","}{$2="";sub(/,,/,",");print $0}' Input_file
        

        gnu-awk 手册:https://www.gnu.org/software/gawk/manual/html_node/Changing-Fields.html

        请务必注意,对现有字段进行分配会更改 $0 的值,但不会更改 NF 的值,即使您将空字符串分配给字段也是如此。”(4.4 更改字段的内容)

        因此,遵循 RavinderSingh13 的第一个解决方案,但不使用,在这种情况下,sub()“该字段仍然存在;它只是有一个空值,由两个冒号分隔”:

        awk 'BEGIN {FS=OFS=","} {$2="";print $0}' file 
        0x01,,0x93,0x65,0xF8
        0x01,,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
        0x01,,0x00,0x76
        

        【讨论】:

        • 这可能应该是对上述答案的评论,并可能纳入编辑!
        • 是的,可能,但我认为了解这一点很重要,这是一个普遍的概念。
        【解决方案6】:

        我的解决方案:

        awk -F, '
        {
            regex = "^"$1","$2
            sub(regex, $1, $0);
            print $0;
        }'
        

        或一行代码: awk -F, '{regex="^"$1","$2;sub(regex, $1, $0);print $0;}' test.txt

        我发现 OFS="," 没有必要

        【讨论】:

          【解决方案7】:

          我会这样做,让file.txt内容为:

          0x01,0xDF,0x93,0x65,0xF8
          0x01,0xB0,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
          0x01,0xB2,0x00,0x76
          

          然后

          awk 'BEGIN{FS=",";OFS=""}{for(i=2;i<=NF;i+=1){$i="," $i};$2="";print}' file.txt
          

          输出

          0x01,0x93,0x65,0xF8
          0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
          0x01,0x00,0x76
          

          说明:我将OFS 设置为空(空字符串),然后对于第二列和下一列,我在开始时添加,。最后,我将现在的逗号和值设置为空。请记住,如果您希望删除第 1 列,则此解决方案需要返工。

          【讨论】:

            【解决方案8】:

            另一种解决方案:

            您可以将输出通过管道传输到另一个 sed 并压缩分隔符。

            $ awk -F, 'BEGIN{OFS=","}{$2=""}1 ' edward.txt  | sed 's/,,/,/g'
            0x01,0x93,0x65,0xF8
            0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
            0x01,0x00,0x76
            $
            

            【讨论】:

              【解决方案9】:

              使用 GNU sed,您可以添加一个数字修饰符来替换非逗号字符后跟逗号的第 n 个匹配项:

              sed -E 's/[^,]*,//2' file
              

              【讨论】:

                【解决方案10】:

                以无正则表达式的方式使用 awk,可以选择删除哪一行:

                awk '{ col = 2; n = split($0,arr,","); line = ""; for (i = 1; i <= n; i++) line = line ( i == col ? "" : ( line == "" ? "" : ","  ) arr[i] ); print line }' test.txt
                

                一步一步:

                {
                col = 2    # defines which column will be deleted
                n = split($0,arr,",")    # each line is split into an array
                                         # n is the number of elements in the array
                
                line = ""     # this will be the new line
                
                for (i = 1; i <= n; i++)   # roaming through all elements in the array
                    line = line ( i == col ? "" : ( line == "" ? "" : "," ) arr[i] )
                    # appends a comma (except if line is still empty)
                    # and the current array element to the line (except when on the selected column)
                
                print line    # prints line
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-09-25
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多