16

Suppose I have a file as follows (a sorted, unique list of integers, one per line):

1
3
4
5
8
9
10

I would like the following output (i.e. the missing integers in the list):

2
6
7

How can I accomplish this within a bash terminal (using awk or a similar solution, preferably a one-liner)?

Jake Sebright
  • 799
  • 8
  • 16

6 Answers6

28

Using awk you can do this:

awk '{for(i=p+1; i<$1; i++) print i} {p=$1}' file

2
6
7

Explanation:

  • {p = $1}: Variable p contains value from previous record
  • {for ...}: We loop from p+1 to the current row's value (excluding current value) and print each value which is basically the missing values
anubhava
  • 761,203
  • 64
  • 569
  • 643
8

Using seq and grep:

seq $(head -n1 file) $(tail -n1 file) | grep -vwFf file -

seq creates the full sequence, grep removes the lines that exists in the file from it.

choroba
  • 231,213
  • 25
  • 204
  • 289
2
perl -nE 'say for $a+1 .. $_-1; $a=$_'
JJoao
  • 4,891
  • 1
  • 18
  • 20
1

Calling no external program (if filein contains the list of numbers):

#!/bin/bash
i=0
while read num; do
    while (( ++i<num )); do
        echo $i
    done
done <filein
1

To adapt choroba's clever answer for my own use case, I needed my sequence to deal with zero-padded numbers.

The -w switch to seq is the magic here - it automatically pads the first number with the necessary number of zeroes to keep it aligned with the second number:

-w, --equal-width     equalize width by padding with leading zeroes

My integers go from 0 to 9999, so I used the following:

seq -w 0 9999 | grep -vwFf "file.txt"

...which finds the missing integers in a sequence from 0000 to 9999. Or to put it back into the more universal solution in choroba's answer:

seq -w $(head -n1 "file.txt") $(tail -n1 "file.txt") | grep -vwFf "file.txt"

I didn't personally find the - in his answer was necessary, but there may be usecases which make it so.

Hashim Aziz
  • 4,074
  • 5
  • 38
  • 68
1

Using Raku (formerly known as Perl_6)

raku -e 'my @a = lines.map: *.Int; say @a.Set (^) @a.minmax.Set;' 

Sample Input:

1
3
4
5
8
9
10

Sample Output:

Set(2 6 7)

I'm sure there's a Raku solution similar to @JJoao's clever Perl5 answer, but in thinking about this problem my mind naturally turned to Set operations.

The code above reads lines into the @a array, mapping each line so that elements in the @a array are Ints, not strings. In the second statement, @a.Set converts the array to a Set on the left-hand side of the (^) operator. Also in the second statement, @a.minmax.Set converts the array to a second Set, on the right-hand side of the (^) operator, but this time because the minmax operator is used, all Int elements from the min to max are included. Finally, the (^) symbol is the symmetric set-difference (infix) operator, which finds the difference.

To get an unordered whitespace-separated list of missing integers, replace the above say with put. To get a sequentially-ordered list of missing integers, add the explicit sort below:

~$ raku -e 'my @a = lines.map: *.Int; .put for (@a.Set (^) @a.minmax.Set).sort.map: *.key;' file
2
6
7

The advantage of all Raku code above is that finding "missing integers" doesn't require a "sequential list" as input, nor is the input required to be unique. So hopefully this code will be useful for a wide variety of problems in addition to the explicit problem stated in the Question.

OTOH, Raku is a Perl-family language, so TMTOWTDI. Below, a @a.minmax array is created, and grepped so that none of the elements of @a are returned (none junction):

~$ 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

jubilatious1
  • 1,999
  • 10
  • 18
  • 1
    First time learning about `raku` ++ – anubhava May 12 '22 at 20:08
  • 1
    @anubhava _"Raku (formerly known as Perl 6) is a sister language, part of the Perl family, not intended as a replacement for Perl, but as its own thing - libraries exist to allow you to call Perl code from Raku programs and vice versa."_ quote from: https://www.perl.org/ – jubilatious1 May 12 '22 at 21:07