1

This question is similar to How can I find the missing integers in a unique and sequential list (one per line) in a unix terminal?.

The difference being is that I want to know if it is possible to specify a starting range to the list

I have noted the following provided solutions:

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

and

perl -nE 'say for $a+1 .. $_-1; $a=$_'

file1 is as below:

5
6
7
8
15
16
17
20

Running both solutions, it gives the following output:

1
2
3
4
9
10
11
12
13
14
18
19

Note that the output start printing from 1.

Question is how to pass an arbitrary starting/minimum to start with and if nothing is provided, assume the number 1 as the starting/minimum number?

9
10
11
12
13
14
18
19

Yes, sometimes you will want the starting number to be 1 but sometimes you will want the starting number as the least number from the list.

benbart
  • 23
  • 4

4 Answers4

2

You can use your awk script, slightly modified, and pass it an initial p value with the -v option:

$ awk 'BEGIN{p=p<1?1:p} {for(i=p; i<$1; i++) print i} {p=p<=$1?$1+1:p}' file1
1
2
3
4
9
10
11
12
13
14
18
19
$ awk -v p=10 'BEGIN{p=p<1?1:p} {for(i=p; i<$1; i++) print i} {p=p<=$1?$1+1:p}' file1
10
11
12
13
14
18
19

The BEGIN block initializes p to 1 if it is not specified or set to 0 or a negative value. The loop starts at p instead of p+1, and the last block assigns $1+1 to p (instead of $1), if and only if p is less or equal $1.

This assumes that the default (1) is the minimum starting number you would want. If you would like to start from 0 or even from a negative number just replace BEGIN{p=p<1?1:p} by BEGIN{p=(p==""?1:p)}:

$ awk -v p=-2 'BEGIN{p=(p==""?1:p)} {for(i=p; i<$1; i++) print i} {p=p<=$1?$1+1:p}' file1
-2
-1
0
1
...
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • thanks this works fine to what am looking. had also tried using p=${x} setting x as an exported variable and that works fine too ... any chance you can advise how to print the existing and missing number as a columnar output? Or do I just print $1? For example 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 – benbart May 02 '22 at 13:42
1

Slight variations of those one-liners to include a start point:

awk

# Optionally include start=NN before the first filename
$ awk 'BEGIN { start= 1 }
       $1 < start { next }
       $1 == start { p = start }
       { for (i = p + 1; i < $1; i++) print i; p = $1}' start=5 file1
9
10
11
12
13
14
18
19
$ awk 'BEGIN { start= 1 }
       $1 < start { next }
       $1 == start { p = start }
       { for (i = p + 1; i < $1; i++) print i; p = $1}' file1
1
2
3
4
9
10
11
12
13
14
18
19

perl

# Optionally include -start=NN before the first file and after the --
$ perl -snE 'BEGIN { $start //= 1 }
             if ($_ < $start) { next }
             if ($_ == $start) { $a = $start }
             say for $a+1 .. $_-1; $a=$_' -- -start=5 file1
9
10
11
12
13
14
18
19
$ perl -snE 'BEGIN { $start //= 1 }
             if ($_ < $start) { next }
             if ($_ == $start) { $a = $start }
             say for $a+1 .. $_-1; $a=$_' -- file1
1
2
3
4
9
10
11
12
13
14
18
19
Shawn
  • 47,241
  • 3
  • 26
  • 60
  • thanks shawn, love this indentation, amazing how fellas here can write these complex scenarios, here's a thought, is it possible to sort of column print the existing number and the missing number as a columnar output of some sort, i suppose using diff can do that – benbart May 02 '22 at 13:36
1

Using Raku (formerly known as Perl_6)

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

Sample Input:

5
6
7
8
15
16
17
20

Sample Output:

9
10
11
12
13
14
18
19

Here's an answer coded in Raku, a member of the Perl-family of programming languages. No, it doesn't address the OP's request for a user-definable starting point. Instead the code above is a general solution that computes the input's minimum Int and counts up from there, returning any missing Ints found up--to the input's maximum Int.

Really need a user-defined lower limit? Try the following code, which allows you to set a $init variable:

~$ raku -e 'my @a=lines.map: *.Int; my $init = 1; .put for (@a.Set (^) ($init..@a.max).Set).sort.map: *.key;' 
1
2
3
4
9
10
11
12
13
14
18
19

For explanation and shorter code (including single-line return and/or return without sort), see the link below.

https://stackoverflow.com/a/72221301/7270649
https://raku.org

jubilatious1
  • 1,999
  • 10
  • 18
0

not as elegant as i hoped :

< file | mawk '
         BEGIN {    _= int(_)^(\
               ( ORS = "")<_) 
         }  { ___[ __= $0 ] }
         END { 
            do { 
                print _ in ___ \
                      ? "" : _ "\n" 
            } while(++_ < __) }' \_=10          
10
11
12
13
14
18
19
RARE Kpop Manifesto
  • 2,453
  • 3
  • 11