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

Check to see if numbers in a column are sequential via command line

在一个文本文件中,我在一列中有一个数字序列,前面有一个短字符串。这是此处示例文件中的第 5 列 "NAME":

SESSION NAME:   session
SAMPLE RATE:    48000.000000
BIT DEPTH:  16-bit
SESSION START TIMECODE: 00:00:00:00.00
TIMECODE FORMAT:    24 Frame
# OF AUDIO TRACKS:  2
# OF AUDIO CLIPS:   2
# OF AUDIO FILES:   2


M A R K E R S  L I S T I N G
#       LOCATION        TIME REFERENCE      UNITS       NAME                                COMMENTS
2       0:00.500        24000               Samples     xxxx0001                            
3       0:03.541        170000              Samples     xxxx0002                            
4       0:05.863        281458              Samples     xxxx0003                            
5       0:08.925        428430              Samples     xxxx0004                            
6       0:10.604        509025              Samples     xxxx0005                            
7       0:13.973        670742              Samples     xxxx0006                            
8       0:15.592        748453              Samples     xxxx0008                            
9       0:19.243        923666              Samples     xxxx0008


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

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

  1. sequential given the range that presently exists in the column.
  2. if there are any duplicates

我也想输出这些结果:

SKIPPED:
xxxx0007

DUPLICATES:
xxxx0008

我能得到的最远的是使用awk来得到我需要的列:

cat <file.txt> | awk '{ print }'

这让我想到了这个:

NAME
xxxx0001
xxxx0002
xxxx0003
xxxx0004
xxxx0005
xxxx0006
xxxx0008
xxxx0008

但我不知道从这里去哪里。

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

任何帮助将不胜感激 谢谢!

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

awk '
NR>1 { gsub("[^0-9]", "", ); count[]++ }
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

输出:

Skipped:
xxxx0007
Duplicates:
xxxx0008
  • 条件 NR>1 用于跳过顶部 header 行。
  • gsub("[^0-9]", "", )</code> 中删除了 non-number 个字符。 结果,<code> 被设置为从第 5 列中提取的数字。
  • 数组count[]计算每个数字出现的次数。如果值 是 0 (或未定义),表示跳过该数字。如果值 大于1,数字重复。
  • END { ... }块被执行所有输入行被处理之后 报告最终结果很有用。

但是,"Skipped/Duplicates" 方法无法很好地检测出以下情况:

#       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

#       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     xxxx0002
4       0:07.050        338446              Samples     xxxx0004
5       0:09.034        433672              Samples     xxxx0005
6       0:12.061        578958              Samples     xxxx0006
7       0:14.111        677333              Samples     xxxx0007
8       0:17.253        828181              Samples     xxxx0008

最好在预期值和实际值之间进行line-by-line比较。那怎么样:

awk '
NR>1 {
    gsub("[^0-9]", "", )
    if ( != NR-1) printf "Line: %d  Expected: xxxx%04d  Actual: xxxx%04d\n", NR, NR-1, 
} ' file.txt

原始示例的输出:

Line: 8  Expected: xxxx0007  Actual: xxxx0008

[编辑]

根据包含更多额外 header 行的修改后的输入文件,如何:

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

输出:

Line: 19  Expected: xxxx0007  Actual: xxxx0008

上面的脚本会跳过这些行,直到找到特定的模式 # LOCATION TIME REFERENCE

  • 如果 f 为真,则执行 f { ... } 块。所以该块被跳过 直到 f 设置为非零值。
  • 如果输入行匹配则执行/^# .../ { ... }块 图案。如果找到,skip 设置为 header 行数,并且 f (flag) 被设置为 1 所以上面的块从下一个开始执行 迭代。

希望这对您有所帮助。