# Find consecutive integers from list of numbers

With a file of integers separated by newlines, I would like to search for consecutive integers, then list the amount of integers that are consecutive per uninterrupted sequence, as well as the direction (ascending or descending) that each sequence is going in.

My file looks something like this:

``````2
3
4
5
1
7
4
5
6
3
2
1
``````

And my desired output would be:

``````4^
3^
3v
``````

With the first character indicating the amount of numbers that are consecutive, and the second character indicating whether the numbers are ascending or descending. Is there a way to do this in bash?

• Really similar: unix.stackexchange.com/q/470073/117549 Commented Jan 19, 2019 at 22:59
• What about `12321`, is that `3^2v` or `2^3v` or `3^3v`? Commented Jan 20, 2019 at 0:11
• @Sparhawk - for my purposes, that would be 3^3v Commented Jan 20, 2019 at 0:22

not in bash but in awk. which is considered fair game in bash/shell script by most. by many. at least by me.

``````func printrun() {
if(run > 1) {
print run""dir
}
}
NR == 1 {
#print \$1" first"
prev = \$1
dir = "-"
run = 1
next
}
\$1 == prev+1 && dir == "v" {
#print \$1" up from down"
printrun()
prev = \$1
dir = "^"
run = 2
next
}
\$1 == prev+1 {
#print \$1" up"
prev = \$1
dir = "^"
run++
next
}
\$1 == prev-1 && dir == "^"  {
#print \$1" down from up"
printrun()
prev = \$1
dir = "v"
run = 2
next
}
\$1 == prev-1 {
#print \$1" down"
prev = \$1
dir = "v"
run++
next
}
{
#print \$1" else"
printrun()
prev = \$1
dir = "-"
run = 1
}
END {
#print "end"
printrun()
}
``````

i tried to compact the code in variations of if and else if chains but i found this variant to be the most clear and readable.

save in `run.awk`

run like this

``````\$ awk -f run.awk inputfile
``````

or pipe input

``````\$ commandproducinginput | awk -f run.awk
``````

explanation:

awk roughly works like this: it will read the input line by line. for each line it will execute the code blocks for which the condition is true.

a code block is the thing in curly braces. the condition is the part before the code block.

``````condition { code block }
``````

`BEGIN` and `END` are special conditions which are true before the first line and after the last line respectively. in this code we have no `BEGIN`. only `END`.

`func` is not a condition. instead it is a function declaration to be used later.

the condition of the first block is `NR == 1`. `NR` is the number of record which practically means line number. in effect this means the block will be executed on the first line and never again. in this block we init the variables to sane values.

this block and most other blocks end with the `next` statement. `next` tells awk to abandon this cycle and load the next line and start the next cycle of looking for which blocks to run. with the `next` in place we effectively created a big if else if chain.

the condition of the next block is `\$1 == prev+1 && dir == "v"`. this tests if the current number is one higher than the previous number and if the direction of the run is currently down. if both are true then we print the ongoing run down and update the variables to start a new run up. if not then this block will not be executed and awk will look for the next block to execute.

the following conditions and blocks are analogous to this one.

the second to last block, the block before the `END` block, is a block without condition. that means it would have been executed for every line. due to the `next` statements in the previous blocks this block will only be executed if no previous block was executed. in effect this block is the "else" of the if else if chain.

this block is reached if the number is neither consecutive up nor down. so the code in this block sets the vars to correspond to an end of run.

in pseudo code the code might look like this:

``````if first line:
init vars and set run to none
else if now going up but was going down:
print ongoing run down and start a run up
else if now going up:
start or continue run up
else if now going down but was going up:
print ongoing run up and start a run down
else if now going down:
start or continue run down
else:
print ongoing run and set run to none
if end of input:
print ongoing run
``````
``````awk 'function prnt(Xdir){ if (c)print c+1, Xdir; c=0 }
(pre+1==\$0){ prev_dir=dir; dir="▲"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=\$0; next }
(pre==\$0+1){ prev_dir=dir; dir="▼"; if(prev_dir!=dir) prnt(prev_dir); c++; pre=\$0; next }
c{ prnt(dir) }
{ pre= \$0}
END{ prnt(dir) }' infile
``````

``````4 ▲
3 ▲
3 ▼
``````