I would like to compute a Napierian logarithm with Bash.
Here is my code using what I found in the internet. The values I use are in output files.
for nn in 1 2 3 4 ; do
for w in 0.5 ; do
a=`grep ' # Final variational ensemble-DFT energy: ' $nn"_"$w.out`
for n in 1000 ; do
b=`grep ' # Final variational ensemble-DFT energy: ' $n"_"$w.out`
done
done
c=`echo "l({$a - $b})" | bc -l`
d=`echo "l({$nn})" | bc -l`
echo $d" "$c >> data_slope.dat
done
I want to plot $d = f($c) from data_slope.dat, but apparently this notation with bc -l doesn't work for me.
I obtain this kind of error :
(standard_in) 1: illegal character: #
(standard_in) 1: syntax error
(standard_in) 1: illegal character: T
(standard_in) 1: syntax error
(standard_in) 1: illegal character: :
(standard_in) 1: syntax error
Whereas I've already done some bash code like this without trying to compute a logarithm, and I didn't get those errors.
The syntax errors are reported by bc. Its syntax for subtraction expects numbers on both sides of the - operand, not strings containing #. The curly braces are wrong, too: you can experiment with
a=3
b=0.2
for expression in "l($a-$b)" "l({$a-$b})" "({#F - #T})" ; do
echo "$expression"
echo "$expression" | bc -l
done
Thanks to your comments I manage to find my mistake.
#Etan Reisner : Indeed my a and b are wrong, I did not grep the values of a and b but the sentence before the values... I should have put ${a:47:16} instead of $a to grep the value of a, which is a real number. Same for $b.
#choroba : I removed the curly braces, now it works.
Related
I have some trouble with such an easy task...
Please find relevant code below:
loewdin_fuk=$(echo $line_fukui|awk '{print $4}')
nbo_fuk=$(echo $line_fukui|awk '{print $5}')
echo "loewdin_fuk $loewdin_fuk nbo_fuk $nbo_fuk"
aver_fuk=$(($loewdin_fuk + $nbo_fuk))
\#aver_fuk=$(echo "scale=4; 0.5*($loewdin_fuk $nbo_fuk)" | bc -l)
The output is:
loewdin_fuk +0.1662 nbo_fuk +0.1865
./collectFukui.sh: line 151: +0.1662 + +0.1865: syntax error: invalid
arithmetic operator (error token is ".1662 + +0.1865")
Using the command line:
aver_fuk=$(echo "scale=4; 0.5*($loewdin_fuk $nbo_fuk)" | bc -l)
leads to following output:
loewdin_fuk +0.1662 nbo_fuk +0.1865
(standard_in) 1: syntax error
I don't get what's wrong... Thank you in advance!
Best,
Me
The problem here is that bc does not consider + to be a unary operator. So +0.1662 +0.1865 is invalid syntax. (It would have worked ok if the first number were negative, because - is a unary operator.)
So if you want to use bc, you need to do something like:
aver_fuk=$(echo "scale=4; 0.5*(0$loewdin_fuk $nbo_fuk)" | bc -l)
Prepending 0 without a space will work whether or not $loewdin_fuk starts with a sign character. If you put a space in between, it would work with values with explicit sign characters, but fail on values without a sign.
I have this piece of code where I am getting (standard_in) 1: syntax error from the third line:
valueInFloat=printf "%.2g" $temp
tempFloat=printf "%.1f" $value2
compare_result=`echo "$tempFloat < $valueInFloat" |bc -l`
if [[ -z $compare_result ]]
then ...
I am trying to do float value comparison in bash.
Note that, if I comment out the third line and put compare_result=0, the error goes away.
There are situations in which printf can generate floating point values that bc won't recognise. Specifically, something like:
pax> printf "%.2g\n" 42456456457357357
4.2e+16
pax> echo '4.2e+16 > 1.0' | bc -l
(standard_in) 1: syntax error
I suggest you stick with the %f variant. It will always generate the form [−]999.999 as per the ISO C standard, which bc will have no trouble with (unless you start getting into infinities or NaNs). The %g variant generates either that format or the %e format [−]9.999e±99 depending on the value and precision requested.
In addition, your test is wrong. The -z test will be true if the string is empty, and your string will either be 1 or 0 depending on the result of the comparison. A better test would be (assuming you wanted to rest if the test was positive:
if [[ ${compare_result} -eq 1 ]]
Either of $tempFloat or $valueInFloat has no value.
I need to do an operation but something is wrong in my code in bash
I have 4 variables, km1, km2, km3, km4.
I want to sum the 4 variables except when the value is "CLOSED"
3.200
CLOSED
1.800
0.600
When I do the following sum, there is an error...I thing my variables are not numeric, any help? How can I force them to be numeric and then do the sum?
let km=$km1+$km3+$km4
echo $km
./sum.sh: line 41: let: km=3.200: syntax error: invalid arithmetic operator (error token is ".200")
km1=3.200
km2=CLOSED
km3=1.800
km4=0.600
total=`LC_ALL=C echo "$km1 $km2 $km3 $km4"|awk '{sum += $1+$2+$3+$4}END {print sum}'`
Not that good with awk but i think the above can help. total the is sum of all vars
There are 2 issues with you code. The first one is that you are trying to work with values other than integers. Bash only does integers. You can round up the values to integers using bc (An arbitrary precision calculator language). The second issue is that you are trying to do math on strings. So consider the code below:
#!/bin/bash
km1=3.200;
km2="CLOSED";
km3=1.800;
km4=0.600;
km1=$(echo "$km1/1" | bc)
km3=$(echo "$km3/1" | bc)
km4=$(echo "$km4/1" | bc)
array=($km1 $km2 $km3 $km4)
for i in ${array[#]}; do
case $i in
*[0-9]*)
(( result+=$i ))
esac
done
echo $result
I have entered this shell script and its showing errors when compiling
echo Enter basic Salary
read bs
if [ $bs -lt 1500 ]
then
hra= echo ´$bs \* 10 / 100´|bc
fi
gs= echo ´$bs + $hra´|bc
echo $gs
The errors are:
(standard_in) 1: illegal character: \302
(standard_in) 1: illegal character: \264
(standard_in) 1: illegal character: \302
(standard_in) 1: illegal character: \264
(standard_in) 1: illegal character: \302
(standard_in) 1: illegal character: \264
(standard_in) 1: illegal character: \302
(standard_in) 1: illegal character: \264
(standard_in) 2: syntax error
One problem is (or, rather, 4 problems are) the use of ´ in place of ' or ".
There is another character in there also causing trouble, unless the acute accent is encoded in UTF-8 or UTF-16†
Another problem is the use of spaces around assignments; these do not fly in the shell. You must not have spaces on either side of the assignment.
echo Enter basic Salary
read bs
if [ "$bs" -lt 1500 ]
then hra=$(echo "$bs * 10 / 100"|bc)
fi
gs=$(echo "$bs + $hra"|bc)
echo $gs
You don't really need the variable gs; you could write:
echo "$bs + $hra" | bc
Note that if bs is not less than 1500, you get a ill-defined value for hra (whatever happens to be left over, or blank if it is unset).
† It looks like you have UTF-8 encoded data.
$ echo "´" | odx
0x0000: C2 B4 0A ...
0x0003:
$ echo "´" | utf8-unicode
0xC2 0xB4 = U+00B4
0x0A = U+000A
$ bc | cat
ibase=16
obase=8
C2
302
B4
264
quit
$
U+00B4 is ACUTE ACCENT in Unicode.
Too many Errors:
As stated by Jonathan, is using ´ in place of `.
Do not use space while assigning values to variables.
Create the data before assigning it to a variable.
For e.g.
hra=echo $bs \* 10 / 100|bc
Also, if the input exceeds 1500, then it will give out the error. So you need to do something with it.
For e.g.
echo "Enter basic Salary"
read bs
if [ $bs -lt 1500 ]
then
hra=echo $bs \* 10 / 100|bc
else
hra=echo $bs \* 5 / 100|bc
fi
gs=echo $bs + $hra|bc
echo $gs
In a text file, test.txt, I have the next information:
sl-gs5 desconnected Wed Oct 10 08:00:01 EDT 2012 1001
I want to extract the hour of the event by the next command line:
hour=$(grep -n sl-gs5 test.txt | tail -1 | cut -d' ' -f6 | awk -F ":" '{print $1}')
and I got "08". When I try to add 1,
14 echo $((hour+1))
I receive the next error message:
./test2.sh: line 14: 08: value too great for base (error token is "08")
If variables in Bash are untyped, why?
See ARITHMETIC EVALUATION in man bash:
Constants with a leading 0 are interpreted as octal numbers.
You can remove the leading zero by parameter expansion:
hour=${hour#0}
or force base-10 interpretation:
$((10#$hour + 1))
what I'd call a hack, but given that you're only processing hour values, you can do
hour=08
echo $(( ${hour#0} +1 ))
9
hour=10
echo $(( ${hour#0} +1))
11
with little risk.
IHTH.
You could also use bc
hour=8
result=$(echo "$hour + 1" | bc)
echo $result
9
Here's an easy way, albeit not the prettiest way to get an int value for a string.
hour=`expr $hour + 0`
Example
bash-3.2$ hour="08"
bash-3.2$ hour=`expr $hour + 0`
bash-3.2$ echo $hour
8
In Short: In order to deal with "Leading Zero" numbers (any 0 digit that comes before the first non-zero) in bash
- Use bc An arbitrary precision calculator language
Example:
a="000001"
b=$(echo $a | bc)
echo $b
Output: 1
From Bash manual:
"bc is a language that supports arbitrary precision numbers with interactive execution
of statements. There are some similarities in the syntax to the C programming lan-
guage. A standard math library is available by command line option. If requested, the
math library is defined before processing any files. bc starts by processing code from
all the files listed on the command line in the order listed. After all files have
been processed, bc reads from the standard input. All code is executed as it is read.
(If a file contains a command to halt the processor, bc will never read from the standard input.)"
Since hours are always positive, and always 2 digits, you can set a 1 in front of it and subtract 100:
echo $((1$hour+1-100))
which is equivalent to
echo $((1$hour-99))
Be sure to comment such gymnastics. :)
The leading 0 is leading to bash trying to interpret your number as an octal number, but octal numbers are 0-7, and 8 is thus an invalid token.
If I were you, I would add some logic to remove a leading 0, add one, and re-add the leading 0 if the result is < 10.
How about sed?
hour=`echo $hour|sed -e "s/^0*//g"`