假设我有一个文件,内容如下(按行排列的整数排序列表,每行一个数字):
1
3
4
5
8
9
10
我希望得到以下输出(即列表中缺失的整数):
2
6
7
如何在Bash终端中使用awk或类似的解决方案(最好是一行代码)来完成此操作?
使用 awk 命令可以做到这一点:
awk '{for(i=p+1; i<$1; i++) print i} {p=$1}' file
2
6
7
说明:
{p = $1}
:变量p
包含前一个记录的值{for ...}
:我们循环从p+1
到当前行的值(不包括当前值),并打印每个值,这些值基本上是缺失的值使用 seq
和 grep
:
seq $(head -n1 file) $(tail -n1 file) | grep -vwFf file -
seq
创建完整的序列,grep
从中删除文件中存在的行。
perl -nE 'say for $a+1 .. $_-1; $a=$_'
seq
的-w
开关-它自动用必要数量的零填充第一个数字,以使其与第二个数字对齐。-w, --equal-width equalize width by padding with leading zeroes
seq -w 0 9999 | grep -vwFf "file.txt"
这个程序可以找到从0000
到9999
序列中缺失的整数。或者换句话说,按照choroba回答的更通用的解决方案:
seq -w $(head -n1 "file.txt") $(tail -n1 "file.txt") | grep -vwFf "file.txt"
-
并不必要,但可能有一些使用情况需要它。如果filein包含数字列表,则不调用任何外部程序:
#!/bin/bash
i=0
while read num; do
while (( ++i<num )); do
echo $i
done
done <filein
raku -e 'my @a = lines.map: *.Int; say @a.Set (^) @a.minmax.Set;'
输入示例:
1
3
4
5
8
9
10
样例输出:
Set(2 6 7)
我相信有一种类似于 @JJoao 聪明的 Perl5 解决方案的 Raku 解决方案,但是在思考这个问题时,我的思维自然而然地转向了 Set
操作。
上面的代码将 lines
读入到 @a
数组中,并将每行映射为 @a
数组中的元素为 Int
,而不是字符串。在第二个语句中,@a.Set
将数组转换为左侧的 Set
,并使用 (^)
运算符。同样在第二个语句中,@a.minmax.Set
将数组转换为第二个 Set
,位于 (^)
运算符的右侧,但是这次因为使用了 minmax
运算符,所有从 min
到 max
的 Int
元素都包括在内。最后,(^)
符号是对称差(中缀)运算符,用于查找差异。
要获取缺失整数的无序空格分隔列表,请将上述的 say
替换为 put
。要获取连续排序的缺失整数列表,请在下面添加显式的 sort
:
~$ raku -e 'my @a = lines.map: *.Int; .put for (@a.Set (^) @a.minmax.Set).sort.map: *.key;' file
2
6
7
@a.minmax
数组,并进行grep
,以便返回@a
元素中的none
(none
连接符):~$ raku -e 'my @a = lines.map: *.Int; .put for @a.minmax.grep: none @a;' file
2
6
7
https://docs.raku.org/language/setbagmix
https://docs.raku.org/type/Junction
https://raku.org
raku
++ - anubhava
NR == 1 { last_number = $1 } ; NR > 1 { for (i = last_number + 1; i < $1; i++) print i; last_number = $1 }
- undefined