Suppose I have the following code
for n in {50..300};
do
(( a = 0.3*$n))
#do something
echo $n
echo $a
done
when I run the code, I received an error, it says
((: a = 0.3*50: syntax error: invalid arithmetic operator (error token is ".3*50")
I know it must be because 0.3 or any decimal number isn't recognizable or perhaps due to some formatting issues, as I previously tried ((a = $n / 2)) which worked fine, much appreciated if anyone can give me a hint.
While this is quite a trivial syntax issue, using shellcheck.net to debug such errors would have been much efficient. Your error line needs to be something like
a=$(echo "0.3*$n" | bc ) # 'echo' to print an arithmetic expression
# feeding it to 'bc' for the actual computation.
Related
I want to perform some arithmetic and floating point arithmetic operations on some variables that I read in from a while loop. My code looks like this:
while read n p qlen slen len; do
random_var=$(( $qlen + 0 )) # gives all zeros, not saving qlen
qcov=$(echo $len / $qlen | bc -l) #len and qlen are nothing, not working
qcov=$( bc <<< "scale=3; $len / $qlen" ) #same reason as above, not working
done < input_file.txt
I am pulling each line in input_file.txt and parsing the data into their respective variable names, n, p, qlen, slen, and len. The input file input_file.txt looks like this:
test1 12.345 123 234 12
test2 23.456 345 678 43
test3 98.765 6537 874 346
...
The problem I am having is when I try to perform some arithmetic operation on any of the variables from the read. I can echo the variables just fine, but as soon as I try to perform any kind of arithmetic manipulation, the values are nothing. I suspect that they are not numerals to begin with, some sort of string type (?). I've tried many integer and floating point arithmetic statements and can't seem to preserve the values in the variables. bc commands, arithmetic expansion, echo piped into bc, the triple <<< for bc, all of these solutions I've found online do not work.
The most common errors I receive are:
strings of nothing
(system-in) error 1: parse error
(system-in) error 2: parse error
I've thought about using an awk but I need to perform these operations on every line, and awk keeps going until the end of the file. Is there still a way to do what I want using an awk? I don't really know.
If anyone has an answer or an alternative way to pull data out of the file, I'd really appreciate it.
Thanks in advance.
UPDATE:
some fiddling around with the code has made me realize that everything in the input_file.txt is being saved into only the first variable n. This is why the other variables are empty and why the echo of all the variables looked correct.
Any ideas why the values are not being saved into the correct variables?
I don't know what you really want to obtain. but it seems something like
awk '{print $5/$3}' input_file.txt
0.097561
0.124638
0.0529295
I'm using bc to do a series of calculation.
I'm calling it though a bash script that first of all puts all the expressions to be calculated in a single variable, the passes them to bc to calculate the results.
The script is something like that:
#!/bin/bash
....
list=""
for frml in `cat $frmlList`
do
value=`echo $frml`
list="$list;$value"
done
echo "scale=3;$list"| bc
the frmlList variable contains a list of expressions that are the output of another program, for simplicity i don't mention every operation, but on its contents are done some sed operations before to assign it to the "value" variable.
In the end, the "list" variable contains a list of expressions separated by semicolon that bc understands.
Now what happens is that in my formula list, sometimes happens that there is a division by 0.
When it happens bc stops its computation giving a "Runtime Error: divide by zero".
I would bc to not end its work on that error, but to skip it and continue with the next formula evaluation.
Is possible to achieve something like that?
The same thing happens in a simpler situation:
echo "scale=2;1+1;1/0;2+2;" | bc
the output is
2
Runtime error (func=(main), adr=17): Divide by zero
I would like to have something like
2
Runtime error (func=(main), adr=17): Divide by zero
4
Thank you in advance :)
Ok, in the end i found a workaround that does the trick quite well.
The idea is to parallelize the execution of bc using subshells, this way if an evaluation fails the other can be still done.
In my script i did something like this:
#!/bin/bash
i=0
for frml in `cat $frmlList`
do
i=$((i+1))
(echo "scale=3;$value"| bc -l extensions.bc > "file_$i.tmp") &
if (( $i % 10 == 0 )); then
wait;
fi # Limit to 10 concurrent subshells.
done
#do something with the written files
I know no simple way to do this. If the expressions are independent, you can try to run them all in bc. If that fails, feed them to bc one by one, skipping the broken ones.
If expressions depend on each other, then you probably need something more powerful than bc. Or you can try to append expression after expression to an input file. If bc fails, remove the last one (maybe restore the file from a backup) and try with the next one.
I run this command both by typing in Terminal and by executing file on CentOS 6.5 64 bits.
let t='.'; echo $t;
Can't believe that it yields such a wierd error:
-bash: let: t=.: syntax error: operand expected (error token is ".")
As far as I know, single-quoted strings should not be parsed. In fact, in the first place, what I wanted to do is:
let $target_path='./files/mp4';
Can anyone please explain this behavior and guide me to stop this wierd act?
Unless you want to evaluate the variable value as an arithmetical expression, you need to assign the variable value like this:
t='.'
let is for calculation of arithmetical expressions and . or ./files/mp4 produces a syntax error in that arithmetical expression. Check help let.
Here comes an example how let can be used:
a="10*2"
echo "$a" # Prints: 10*2
let a="10*2"
echo "$a" # Prints: 20
If you followed the discussion below you may have noticed that even for mathematical expressions let isn't the best choice. This is because you can use ARITHMETIC EXPANSION in that case which is defined by POSIX in opposite to let. Using ARITHMETIC EXPANSION the above example would look like this:
a=$((10*2))
echo "$a" # Prints: 20
Check this articles for further information:
let
arithmetic expressions
Using let here is not right.
You can do like this:
AMD$ t='.'
AMD$ echo $t
.
AMD$ t='./files/mp4'
AMD$ echo $t
./files/mp4
I'm trying to write a shell program that, given an argument, prints the name of the program and every odd word in the argument (that is, not even words). However, I am not getting the expected result. Upon tracing my program, I notice that, despite modulus returning values of 1 on odd words (say, the 5th word, 5 % 2 = 1), the program still treats the result as 0 (an even word) and doesn't print the word. What might be going wrong here?
Included here is my code and the traced output to see exactly what I am getting. (Sorry for not including the code as text, I'm new to vim and don't know copy/paste yet)
$result (needs a dollar sign )
Change echo \$$# to echo $1. But it would probably be simpler to re-write the script:
#!/bin/sh
echo $0
while [ $# -gt 0 ]; do
expr $# % 2 > /dev/null && echo $1
shift
done
SYNTAX:
while read l
do
export filename=$l
if [[ `echo $filename | sed -n 's:TEST.*/TEST:&:p'` -ne 0 ]];
then
echo "both are same : $filename"
else
echo "diff: $filename"
fi
done < scripts2.txt*
Problem: Normally its working fine. But for the below data it throws syntax error...
<TEST><![BIGDATA[$EXECUTE SCRIPT ON ALL SERVER $WELCOME#]]></TEST>
Pls let me know what was the exact problem is????
As a general rule, don't try to parse XML/HTML with regular expressions. XML is not a regular language, and you will run into an endless stream of problems. What is it that you are ultimately trying to do? There's probably an easier way to approach the problem.
It is hard to understand what you wish to perform. The obvious mistake in the code above is that you are trying to make an arithmetic comparison (-ne) with something that is not a number.
Your echo ... | sed ... expression for the input above, should produce the string "<&>" and you are testing if this is not equal to zero.
Again, clarifying your intentions would enable other to help you.