Bash script to print the smallest floating point number in a row that is not 0


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Bash script to print the smallest floating point number in a row that is not 0
# 8  
Old 11-03-2018
Hi LMHmedchem,
Well done. I see no reason why the code you have will not meet your requirements.

You might want to consider this alternative that should be slightly faster (since it doesn't split or sort the input, and only looks at each field once):
Code:
#!/bin/sh

# assumes that the input file has a header row
# assumes that the first column is the index and the second column is a name
# assumes that all columns after the first two contain data

# input file name (defaults to "file"
input_file=${1:-file}
# output file name (defaults to "output"
output_file=${2:-output}

awk '
BEGIN {	FS = OFS = "\t"
}
NR > 1 {m = $3
	for(i = 4; i <= NF; i++)
		if($i && ($i < m || !m))
			m = $i
	if(m)	print $1, $2, m
}' "$input_file" > "$output_file"

Note that even if you don't want default filenames to be supplied if you invoke your script with less than two operands, you should still quote the filenames in the last line of your script in case someone invokes your script with a quoted operand containing an IFS character.
These 2 Users Gave Thanks to Don Cragun For This Post:
# 9  
Old 11-03-2018
Quote:
Originally Posted by Don Cragun
Hi LMNmedchem,
Well done. I see no reason why the code you have will not meet your requirements.

You might want to consider this alternative that should be slightly faster (since it doesn't split or sort the input, and only looks at each field once):
Code:
#!/bin/sh

# assumes that the input file has a header row
# assumes that the first column is the index and the second column is a name
# assumes that all columns after the first two contain data

# input file name (defaults to "file"
input_file=${1:-file}
# output file name (defaults to "output"
output_file=${2:-output}

awk '
BEGIN {	FS = OFS = "\t"
}
NR > 1 {m = $3
	for(i = 4; i <= NF; i++)
		if($i && ($i < m || !m))
			m = $i
	if(m)	print $1, $2, m
}' "$input_file" > "$output_file"

Note that even if you don't want default filenames to be supplied if you invoke your script with less than two operands, you should still quote the filenames in the last line of your script in case someone invokes your script with a quoted operand containing an IFS character.
Thank you for the solution. I have not seen that syntax to supply a default argument. I have always just tested the value of the argument and set a value if there isn't one. Your suggestion is much preferable because it's not always easy to tell which argument is missing.

If I understand, you set the IO delimiters, and then start with the second row NR > 1. You assign the value of the third element to m, m = $3, and then compare each other element to m starting with element 4 up to the number of fields, for(i=4; i<=NF; i++).

The comparison, if($i && ($i < m || !m)), is a bit unclear to me. I would guess that if($1) is true if $i is not 0, like evaluating a boolean. The if(($i < m) keeps track of the lowest value but I don't know what the ||!m "or not m" does.

Also, is there any case where if(m) print $1, $2, m will not evaluate as true? I guess if $3=0 and all the rest of the elements are also 0 that statement will not be true. Is that how you trap against all 0 values in a row? If so, I would probably add an else there to print the id and name also with a user message to keep the output fully determined.

You haven't had to explicitly insert the tabs to the print statement since you specified the delimiter with OFS.

I have tried this with input where 0 is 0.0 and 0.0000 and it still works. How does that work with no explicit types?

Sorry for all the questions.

Thanks,

LMHmedchem
# 10  
Old 11-03-2018
Quote:
Originally Posted by LMHmedchem
Thank you for the solution. I have not seen that syntax to supply a default argument. I have always just tested the value of the argument and set a value if there isn't one. Your suggestion is much preferable because it's not always easy to tell which argument is missing.
Note that if you want to use the default value for the 1st operand and specify a different (non-default) value for the 2nd operand, you still have to supply both operands. To specify a default input filename of "file" and a non-default output filename of "new-output", you can use either:
Code:
your_script_name file new-output

or:
Code:
your_script_name "" new-output

Quote:
If I understand, you set the IO delimiters, and then start with the second row NR > 1. You assign the value of the third element to m, m = $3, and then compare each other element to m starting with element 4 up to the number of fields, for(i=4; i<=NF; i++).

The comparison, if($i && ($i < m || !m)), is a bit unclear to me. I would guess that if($1) is true if $i is not 0, like evaluating a boolean. The if(($i < m) keeps track of the lowest value but I don't know what the ||!m "or not m" does.
Yes.

The variable m holds the minimum found so far in columns 3 through NF on the current input line (or the zero from column 3 if all values seen so far are zero). The if($i && ...) prevents the current column from resetting m if $i is zero or an empty string. If that condition is met, the $i < m || !m is used to reset m if the current column value is less than any value found earlier on the line or if the current value is the first non-zero value we have seen on this line but is greater than zero.
Quote:
Also, is there any case where if(m) print $1, $2, m will not evaluate as true? I guess if $3=0 and all the rest of the elements are also 0 that statement will not be true. Is that how you trap against all 0 values in a row? If so, I would probably add an else there to print the id and name also with a user message to keep the output fully determined.
I used that code because it produces no output if all columns on a line have zero (or empty string) values just like the code you used to print results:
Code:
             for(x in line_array) {
                if(line_array[x] != 0) { print id "\t" name "\t" line_array[x];  break; }
             }

If you want to print whatever was in field 3 if all values are zero, change:
Code:
	if(m)	print $1, $2, m

to:
Code:
	print $1, $2, m

If you want alternative text to be printed instead you can either use something like:
Code:
	if(m)	print $1, $2, m
	else	print $1, $2, "all-zero"

or more concisely:
Code:
	print $1, $2, m ? m : "all-zero"

Quote:
You haven't had to explicitly insert the tabs to the print statement since you specified the delimiter with OFS.
Yes.
Quote:
I have tried this with input where 0 is 0.0 and 0.0000 and it still works. How does that work with no explicit types?
When both values being compared are numeric values, awk performs a numeric comparison and all zero values compare equal.
Quote:
Sorry for all the questions.

Thanks,

LMHmedchem
Never apologize for asking questions. That is why we're here and that is how you learn.
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

Comparison of floating point numbers in bash

I have the following code snippet in bash if ]; then minm=`echo "$diff" | bc` fi It works well for most of the cases. However lets say diff is -0.17 and minm is -0.0017. In such a case the comparison seems to fail. Is the correct way to compare a mixture of positive and... (12 Replies)
Discussion started by: ngabrani
12 Replies

2. Shell Programming and Scripting

Convert floating point to a number

Hello Guys, I have a floating point number 1.14475E+15 I want to convert this number in to full number (Integer or Big integer). I tried couple of functions it did not work. When I use INT=${FLOAT/.*} I am getting value as 1. I don't want a truncated value #!/bin/bash #... (9 Replies)
Discussion started by: skatpally
9 Replies

3. Shell Programming and Scripting

[BASH] Floating point exception

Heyas I have a script (vhs - video handler script, using ffmpeg) to encode videos. It also encodes a dvd, but until now just non-copy-protected ones, so i've tried to add/implement a vobcopy wrapper to be used by my script. At first it looked quite fine, but when changing from the first VOB... (9 Replies)
Discussion started by: sea
9 Replies

4. Shell Programming and Scripting

Bash Floating point math with bc

Hello Everyone, I am currently working on a script to calculate optimal tcp window size the formula that I am following is 2 x (bandwith speed /8 * Round Trip Time ) = x This is what I have so far #!/bin/bash echo "Enter connection speed" << Get the speed of the Connection from... (3 Replies)
Discussion started by: bmfmancini
3 Replies

5. Shell Programming and Scripting

[BASH] Regex for floating point number

Hey again, I have a basic regex that tests if a number is a float. Thank you. (5 Replies)
Discussion started by: whyte_rhyno
5 Replies

6. Shell Programming and Scripting

problem with floating point number loops

Hey, I guess I am just to stupid and am not seeing the "wood for the trees", but I am always getting strange errors. I want to create a mesh with coordinates like: x y z 3.1 3.0 0.75 0 0 1 3.1 2.9 0.75 0 0 1 3.1 2.8 0.75 0 0 1 3.1 2.7 0.75 0 0 1 3.0 ... (10 Replies)
Discussion started by: ergy1983
10 Replies

7. Shell Programming and Scripting

floating point number problem

Hello folks I Hope everyone is fine. I am calculating number of bytes calculation from apache web log. awk '{ sum += $10 } END { print sum }' /var/httpd/log/mydomain.log 7.45557e+09 it show above number, what should i do it sow number like 7455, i mean if after decimal point above 5 it... (5 Replies)
Discussion started by: learnbash
5 Replies

8. Shell Programming and Scripting

floating point not recognized by printf in bash

Dear all, I have the following question. Let's say that I have the following script #!/bin/bash value=0.4987865 a=` printf "%6.2f" $value ` b=`echo $value + $value | bc -l` echo $a echo $b exit And the exit is: 0,00 .9975730 Thus, the problem is that the printf order does not... (2 Replies)
Discussion started by: josegr
2 Replies

9. Shell Programming and Scripting

using bc with floating point number in files

Hi, I' using bash and I would like to use "bc" to compute the ratio of of two numbers and assign the ratio to a variable. The numbers are in a file, e.g. 196.304492 615.348986 Any idea how to do it? N.B. I cannot change the file to have 196.304492 / 615.348986 as the file is produced by... (14 Replies)
Discussion started by: f_o_555
14 Replies

10. Shell Programming and Scripting

BASH: floating point exception

Hi, guys, today, I have copied a simple script which runs correctly on a computer to another one. But, the latter informs me: Floating point exception! @ ./command_module a b c where command_module is the module compiled by myself. So, I have fixed it by following steps: 1.... (5 Replies)
Discussion started by: mapleleaves
5 Replies
Login or Register to Ask a Question