Jary
Jary

Reputation: 1521

Bash scripting: Find minimum value in a script

I am writing a script that finds the minimum value in a string. The string is given to me with a cat <file> and then I parse each number inside that string. The string only contains a set of numbers that is separated by spaced.

This is the code:

echo $FREQUENCIES
for freq in $FREQUENCIES
do
    echo "Freq: $freq"
    if [ -z "$MINFREQ" ]
    then
        MINFREQ=$freq
        echo "Assigning MINFREQ for the first time with $freq"
    elif [ $MINFREQ -gt $freq ]
    then
        MINFREQ=$freq
        echo "Replacing MINFREQ with $freq"
    fi
done

Here is the output I get:

800000 700000 600000 550000 500000 250000 125000 
Freq: 800000
Assigning MINFREQ for the first time with 800000
Freq: 700000
Replacing MINFREQ with 700000
Freq: 600000
Replacing MINFREQ with 600000
Freq: 550000
Replacing MINFREQ with 550000
Freq: 500000
Replacing MINFREQ with 500000
Freq: 250000
Replacing MINFREQ with 250000
Freq: 125000
Replacing MINFREQ with 125000
Freq: 
: integer expression expected

The problem is that the last line, for some reason, is empty or contain white spaces (I am not sure why). I tried testing if the variable was set: if [ -n "$freq" ] but this test doesn't seem to work fine here, it still goes through the if statement for the last line.

Could someone please help me figure out why the last time the loop executes, $freq is set to empty or whitespace and how to avoid this please?

EDIT:

using od -c feeded with echo "<<$freq>>"

0000000   <   <   8   0   0   0   0   0   >   >  \n
0000013
0000000   <   <   7   0   0   0   0   0   >   >  \n
0000013
0000000   <   <   6   0   0   0   0   0   >   >  \n
0000013
0000000   <   <   5   5   0   0   0   0   >   >  \n
0000013
0000000   <   <   5   0   0   0   0   0   >   >  \n
0000013
0000000   <   <   2   5   0   0   0   0   >   >  \n
0000013
0000000   <   <   1   2   5   0   0   0   >   >  \n
0000013
0000000   <   <  \r   >   >  \n
0000006

There seems to be an extra \r (from the file).

Thank you very much!

Upvotes: 4

Views: 5634

Answers (5)

Zombo
Zombo

Reputation: 1

echo $FREQUENCIES | awk '{for (;NF-1;NF--) if ($1>$NF) $1=$NF} 1'
  • compare first and last field
  • set first field to the smaller of the two
  • remove last field
  • once one field remains, print

Example

Upvotes: 0

smilyface
smilyface

Reputation: 5521

Data : 10, 10.2, -3, 3.8, 3.4, 12

Minimum : echo -e "10\n10.2\n-3\n3.8\n3.4\n12" | sort -n | head -1
Output: -3

Maximum : echo -e "10\n10.2\n-3\n3.8\n3.4\n12" | sort -nr | head -1
Output: 12


How ? :
1. Print line by line
2. sort for numbers (Reverse for getting maximum)
3. print first line alone.
Simple !!

This may not be a good method. But easy for learners. I am sure.

Upvotes: 0

ata
ata

Reputation: 2065

If you are using bash you have arithmetic expressions and the "if unset: use value and assign" parameter substitution:

#!/bin/bash
for freq in "$@"; do
    (( minfreq = freq < ${minfreq:=freq} ? freq : minfreq ))
done
echo $minfreq

use:

./script 800000 700000 600000 550000 500000 250000 125000

Upvotes: 0

Zsolt Botykai
Zsolt Botykai

Reputation: 51653

For the error problem: you might have some extra white space in $FREQUENCIES?

Another solution with awk

echo $FREQUENCIES | awk '{min=$1;for (i=1;i++;i<=NF) {if ( $i<min ) { min=$i } } ; print min }'

If it's a really long variable, you can go with:

echo $FREQUENCIES | awk -v RS=" " 'NR==1 {min=$0} {if ( $0<min ) { min=$0 } } END {print min }'

(It sets the record separator to space, then on the very first record sets the min to the value, then for every record check if it's smaller than min and finally prints it.

HTH

Upvotes: 0

Manny D
Manny D

Reputation: 20724

If you're only working with integer values, you can validate your string using regex:

elif [[ $freq =~ ^[0-9]+$ && $MINFREQ -gt $freq ]]

Upvotes: 2

Related Questions