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
12321
, is that3^2v
or2^3v
or3^3v
?