代码之家  ›  专栏  ›  技术社区  ›  Roger Costello

如何将一系列字段名输入AWK程序,并让AWK程序检查文件中是否存在字段名?

awk
  •  0
  • Roger Costello  · 技术社区  · 1 周前

    field-names.txt包含字段名列表:

    AB_CODE
    ACFT_CODE
    AC_TYPE
    ADD_INFO
    AKA
    ALT
    ALT1_DESC
    ALT2_DESC
    ALT3_DESC
    

    对于每个字段名,我想打印第一行包含此字段名的文件(以空格分隔的字段列表)。以下是我所尝试的:

    在a bash 我在命令行中输入了以下内容:

    cat field-names.txt | awk 'BEGIN { getline fieldname; print fieldname }
            
    NR == 1 && $0 ~ /fieldname/ { print FILENAME }' **/*.TXT
    

    这会产生错误的结果。正确的方法是什么?

    2 回复  |  直到 1 周前
        1
  •  1
  •   anubhava    1 周前

    这个 awk 解决方案应该适合您:

    awk 'FNR == NR {
       rx = (rx != "" ? rx "|" : "") $1
       next
    }
    FNR == 1 && " " $0 " " ~ " (" rx ") " {
       print FILENAME
    }' field-names.txt **/*.TXT
    

    首先,我们构建一个正则表达式 | 在每一行之间 field-names.txt 在第一块 FNR == NR 。然后,我们使用该正则表达式与使用该正则函数的每一行进行匹配。我们在第一行和正则表达式前加上空格作为前缀和后缀 确保我们只匹配整个单词,而不是部分单词 .


    为了优化,我们可以这样做,只构造一次完整的正则表达式:

    awk 'FNR == NR {
       rx = (rx != "" ? rx "|" : "") $1
       pNR = NR
       next
    }
    NR == pNR+1 {
       rx = " (" rx ") "
    }
    FNR == 1 && " " $0 " " ~ rx {
       print FILENAME
       nextfile
    }' field-names.txt **/*.TXT
    
        2
  •  1
  •   jhnc    1 周前

    一种不使用正则表达式的替代方法,因为它显示的字段名列表只是简单的字符串:

    awk '
        NR==FNR {
            fieldnames[$0]
            next
        }
        
        FNR==1 {
            for (i=NF; i>0 && !($i in fieldnames); --i)
                ;
            if (i)
                print FILENAME
            nextfile
        }
    ' field-names.txt **/*.TXT
    
    • 从第一个文件加载字段名称列表
    • 处理每个后续文件的第一行
      • 检查列表中是否有任何字段
      • 如果i>;0,循环提前中止,因为找到了匹配项
      • 甚至不用费心去看剩下的行

    此代码还接受行首和行尾的字段名。