作为替代方案,您可以使用以下 awk 命令:
cat series.awk
function prnt(delim) {
printf "%s%s", s, (p > s ? "-" p : "") delim
}
BEGIN {
RS=","
}
NR==1 {
s = $1
}
p < $1-1 {
prnt(RS)
s = $1
}
{
p = $1
}
END {
prnt(ORS)
}
现在运行它:
$> foo="1,2,3,6,7,8,11,13,14,15,16,17"
$> awk -f series.awk <<< "$foo"
1-3,6-8,11,13-17
$> foo="1,3,6,7,8,11,13,14,15,16,17"
$> awk -f series.awk <<< "$foo"
1,3,6-8,11,13-17
$> foo="1,3,6,7,8,11,13,14,15,16,17,20"
$> awk -f series.awk <<< "$foo"
1,3,6-8,11,13-17,20
这里是做同样事情的单行:
awk 'function prnt(delim){printf "%s%s", s, (p > s ? "-" p : "") delim}
BEGIN{RS=","} NR==1{s = $1} p < $1-1{prnt(RS); s = $1} {p = $1}END {prnt(ORS)}' <<< "$foo"
在这个 awk 命令中,我们保留 2 个变量:
-
p 用于存储上一行的编号
-
s 用于存储需要打印的范围的开始
工作原理:
- 当
NR==1 我们将s 设置为第一行的编号
- 当
p 小于 (current_number -1) 或$1-1 时,表明我们有一个序列中断,我们需要打印范围。
- 我们使用函数
prnt 进行打印,它只接受一个作为结束分隔符的参数。当 prnt 从 p < $1-1 { ...} 块调用时,我们将 RS 或逗号作为结束分隔符传递,当它从 END{...} 块调用时,我们将 ORS 或换行符作为分隔符传递。
- 在
p < $1-1 { ...} 内部,我们将s(起始范围)重置为$1
- 处理完每一行后,我们将
$1 存储在变量p 中。
-
prnt 使用 printf 进行格式化输出。它总是首先打印起始编号s。然后它会检查是否是p > s 并打印连字符后跟p 如果是这样的话。