Bash 通过命令行检查列中的数字是否连续

Bash 通过命令行检查列中的数字是否连续,bash,awk,command-line,number-formatting,string-parsing,Bash,Awk,Command Line,Number Formatting,String Parsing,在文本文件中,我在一列中有一个数字序列,前面有一个短字符串。这是示例文件中“名称”下的第5列: 在上面的示例中,0007缺失,0008重复 因此,我希望能够检查这些数字是否为: 给定列中当前存在的范围 如果有重复的 我还想输出这些结果: SKIPPED: xxxx0007 DUPLICATES: xxxx0008 我能得到的最远的结果是使用awk获得我需要的列: cat | awk'{print$5}' 这让我想到: NAME xxxx0001 xxxx0002 xxxx0003 xxxx

在文本文件中,我在一列中有一个数字序列,前面有一个短字符串。这是示例文件中“名称”下的第5列:


在上面的示例中,0007缺失,0008重复

因此,我希望能够检查这些数字是否为:

  • 给定列中当前存在的范围
  • 如果有重复的
  • 我还想输出这些结果:

    SKIPPED:
    xxxx0007
    
    DUPLICATES:
    xxxx0008
    
    我能得到的最远的结果是使用
    awk
    获得我需要的列:

    cat | awk'{print$5}'

    这让我想到:

    NAME
    xxxx0001
    xxxx0002
    xxxx0003
    xxxx0004
    xxxx0005
    xxxx0006
    xxxx0008
    xxxx0008
    
    但我不知道该从这里走到哪里

    我是否需要循环遍历列表项并进行解析,以便只获取数字,然后开始与下一行进行比较

    任何帮助都将不胜感激
    谢谢大家!

    作为起点,请尝试以下操作:

    awk '
    NR>1 { gsub("[^0-9]", "", $5); count[$5]++ }
    END {
        print "Skipped:"
        for (i=1; i<NR; i++)
            if (count[i] == 0) printf "xxxx%04d\n", i
        print "Duplicates:"
        for (i=1; i<NR; i++)
            if (count[i] > 1) printf "xxxx%04d\n", i
    } ' file.txt
    
    • 条件
      NR>1
      用于跳过顶部标题行
    • gsub(“[^0-9]”,“,$5)
      $5
      中删除非数字字符。 因此,
      $5
      被设置为从第5列提取的数字
    • 数组
      count[]
      统计每个数字的发生次数。如果值 是
      0
      (或未定义),表示跳过该数字。如果值 大于
      1
      ,则该数字重复
    • 处理完所有输入行后执行
      END{…}
      块 报告最终结果是有用的
    但是,“跳过/重复”方法无法很好地检测以下情况:

    #       LOCATION        TIME REFERENCE      UNITS       NAME            COMMENTS
    1       0:00.500        24000               Samples     xxxx0001
    2       0:02.888        138652              Samples     xxxx0003
    3       0:04.759        228446              Samples     xxxx0004
    4       0:07.050        338446              Samples     xxxx0005
    5       0:09.034        433672              Samples     xxxx0006
    6       0:12.061        578958              Samples     xxxx0007
    7       0:14.111        677333              Samples     xxxx0008
    8       0:17.253        828181              Samples     xxxx0009
    

    最好在预期值和实际值之间进行逐行比较。那么:

    awk '
    NR>1 {
        gsub("[^0-9]", "", $5)
        if ($5 != NR-1) printf "Line: %d  Expected: xxxx%04d  Actual: xxxx%04d\n", NR, NR-1, $5
    } ' file.txt
    
    awk '
    f {
        gsub("[^0-9]", "", $5)
        if ($5 != NR-skip) printf "Line: %d  Expected: xxxx%04d  Actual: xxxx%04d\n", NR, NR-skip, $5
    }
    /^#[[:blank:]]+LOCATION[[:blank:]]+TIME REFERENCE/ {
        skip = NR
        f = 1
    }
    ' file.txt
    
    原始示例的输出:

    Line: 8  Expected: xxxx0007  Actual: xxxx0008
    
    [编辑]

    根据包含更多额外标题行的修订输入文件,如何:

    awk '
    NR>1 {
        gsub("[^0-9]", "", $5)
        if ($5 != NR-1) printf "Line: %d  Expected: xxxx%04d  Actual: xxxx%04d\n", NR, NR-1, $5
    } ' file.txt
    
    awk '
    f {
        gsub("[^0-9]", "", $5)
        if ($5 != NR-skip) printf "Line: %d  Expected: xxxx%04d  Actual: xxxx%04d\n", NR, NR-skip, $5
    }
    /^#[[:blank:]]+LOCATION[[:blank:]]+TIME REFERENCE/ {
        skip = NR
        f = 1
    }
    ' file.txt
    
    输出:

    Skipped:
    xxxx0007
    Duplicates:
    xxxx0008
    
    Line: 19  Expected: xxxx0007  Actual: xxxx0008
    
    上面的脚本跳过这些行,直到找到特定的模式
    #位置时间参考

    • 如果
      f
      为真,则执行
      f{…}
      块。因此,将跳过该块 直到
      f
      设置为非零值
    • 如果输入行与 图案如果找到,
      skip
      设置为标题行数和
      f
      (标志)设置为1,以便从下一个开始执行上一个块 迭代

    希望这能有所帮助。

    您为什么尝试使用awk而不是更高级的语言(如perl、python、Java等)来实现这一点。我不太确定如何通过1(一)次遍历来实现这一点。即使在
    awk
    (我相信这是可能的),代码维护起来也会很复杂。@azbarcea我没有在perl、Python或任何其他语言中尝试过它们,因为我不太精通!我知道这在更高级别上更容易实现,但我决心在命令行上找到实现方法!!这同样有效!!但是,在下面的示例中,我如何处理顶部有多余行的情况呢?我已经根据情况更新了答案。你能测试一下吗?它适用于带有额外行的新文本模式!然而,我仍然希望只看到跳过或重复的数字,而不是整个列表。我的实际文本文件案例有200多行,因此我希望看到一个较短的列表。现在,您可能已经了解了如何报告跳过或重复的行(在我的初始答案中),以及如何处理额外的标题行(在我的上一个答案中)。通过组合这些片段,您可以编写您想要的版本。如果您仍然有问题,请发布1)您的代码,2)复制问题的最小输入行集,3)预期输出。然后我们可以帮你完成代码。祝你好运我在回答中加了一些解释。希望它能帮助您理解代码。