4

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!

Jary
  • 1,501
  • 3
  • 24
  • 35
  • I suggest using 'echo "<<$freq>>"' in the loop, possibly feeding the result to 'od -c'. That should tell you what is going on during the last iteration. Also look at the data file hard. – Jonathan Leffler Nov 21 '11 at 22:05
  • It prints: <<800000>> <<700000>> <<600000>> <<550000>> <<500000>> <<250000>> <<125000>> >> , then it waits for something. – Jary Nov 21 '11 at 22:10
  • I will update with od -c in my initial post. – Jary Nov 21 '11 at 22:12
  • It has an extra \r in the file, unfortunately, I am not making the file nor can I modify it. – Jary Nov 21 '11 at 22:14

5 Answers5

2

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

elif [[ $freq =~ ^[0-9]+$ && $MINFREQ -gt $freq ]]
Manny D
  • 20,310
  • 2
  • 29
  • 31
0

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.

smilyface
  • 5,021
  • 8
  • 41
  • 57
0
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

Zombo
  • 1
  • 62
  • 391
  • 407
0

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

Zsolt Botykai
  • 50,406
  • 14
  • 85
  • 110
  • I am getting this: awk: program limit exceeded: maximum number of fields size=32767 FILENAME="-" FNR=1 NR=1 – Jary Nov 21 '11 at 21:59
  • Oh, then your `$FREQUENCIES` is not the same as in you example :-) Anyway I'll update my answer to work around that. – Zsolt Botykai Nov 21 '11 at 22:59
0

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
ata
  • 2,045
  • 1
  • 14
  • 19