我有一个十六进制数字列表。我想检查一下它们是否按顺序排列。也就是说,它们应该是连续的数字,按升序排列。换句话说,每一行到下一行的增量应该是 1。
十六进制数示例列表:
85AF
85B0
85B1
85B2
85B3
85B4
85B5
85B6
85B7
85B8
85B9
85BA
85BB
85BC
85BD
85BE
85BF
85C0
事实上,我有超过 500 个号码需要检查。
期望的输出:
All numbers are in sequence
(or)
Numbers are not in sequence.
这是在 Solaris 上,使用 ksh。
答案1
如果输出是十进制的,awk 可以很容易地做到这一点,但它不能解析十六进制数字(至少标准 awk 不能,某些版本如 GNU awk 可以)。您可以使用bc
它来进行转换。这适用于所有 POSIX 系统。
{ echo "ibase=16"; cat input.txt; } | bc |
awk 'NR==1 {origin = $0-1}
$0!=origin+NR {print "Out-of-sequence number at line", NR; exit(1)}' >&2
答案2
正如另一个答案中所述,在 awk 中执行此操作会很好,但是古老的 awk(可能在 Solaris 中可用)不理解十六进制数字。
一个快速的解决方案是使用wc -l
一些 ksh 数学:
#! /bin/ksh
first="0x$(head -n1 infile)"
last="0x$(tail -n1 infile)"
lines=$(wc -l <infile)
if [[ "$(( last - first + 1 - lines ))" -eq 0 ]]; then
echo "All numbers are in sequence."
else
echo "Numbers are not in sequence."
fi
答案3
这是一种选择:
while read x; do echo $((16#$x)); done <yourfile | awk 's && $1!=s+1{exit(1)}{s=$1}'
此 shell 命令将产生 1(失败时)和 0(成功时)的退出状态。该命令可以在 if 子句中使用,如下所示,以产生所需的输出:
if while read x; do echo $((16#$x)); done < yourfile | awk 's && $1!=s+1{exit(1)}{s=$1}'
then echo All numbers are in sequence
else echo Numbers are not in sequence
fi
(请注意,您需要将名称“yourfile”替换为包含十六进制数字序列的文件名。)
您还可以省略 shell 循环并使用 GNUawk
的选项-n
直接处理十六进制数字:
if sed 's/^/0x/' <yourfile | awk -n 's && $1+0!=s+1{exit(1)}{s=$1+0}'
then echo All numbers are in sequence
else echo Numbers are not in sequence.
fi
注意:这里使用 sed 来创建十六进制数字的语法预期格式(带有前导0x
)。
答案4
如果您想要严格的序列,可以通过生成标准具序列并将其与文件进行比较来轻松完成
[ $(comm --nocheck-order -3 \
<(sed '/\S/!d' file) \
<(printf "%X\n" \
$(seq $((16#$(sed '/./!d;q' file))) \
$((16#$(tac file|sed '/./!d;q')))))) ] &&
echo 'Numbers are not in sequence' ||
echo 'All numbers are in sequence'
只是为了检查所有数字是否都是十六进制:
sed '/^[[:xdigit:] ]*$/!{
s/.*/Numbers are not in sequence: &/
q
}
$! d
s/.*/All numbers are in sequence/' hexadecimal_number.list
/^[[:xdigit:] ]*$/
检查行中是否只有十六进制符号和空格(或没有 - 空行)!
反向匹配,因此{}
只要存在上述以外的其他符号就执行命令s/.*/.../;q
s
用打印行代替 uit 脚本中的Numbers are not in sequence
所有行q
$! d
如果脚本没有执行上一个(模式匹配)并且如果行不是最后d
一行,则它从下一行开始s/.*/.../
如果脚本到达最后一行(因此所有行都匹配模式),则通过打印s
替换最后一行All numbers are in sequence