Escape brackets in input - bash

I'm trying to write a quick script to pass simple calculations through to bc, however when I try a calculation involving brackets I get the following error:
-bash: syntax error near unexpected token `('
How do I write the script to escape any characters given to it?
This is the code I have now:
calc()
{
echo "$*" | bc
}
And I call it with things like:
calc 100 + 10 + (10 * 10)
Quoting the input works but I'd like to not have to (I'm clearly lazy enough to be trying to make adding numbers easier).

calc '100 + 10 + (10 * 10)'
calc 100 + 10 + '(10 * 10)'
calc 100 + 10 + \(10 \* 10\)
The error is not in calc() but in the code calling it. Parentheses and asterisks are special characters in the shell so you need to quote them. There's nothing you can do within calc() since the shell's barfing before it even calls it.
Quoting the input works but I'd like to not have to.
It's unavoidable. Sorry!

Related

Bash error message: syntax error near unexpected token '|'

I was creating a program that calculates the area of circle, but bash doesnt compile and execute due to error message in the title. Here is my code:
elif [ $num -le 6 ] && [ $num -ge 4 ]
then
read -p "Enter radius: " radius
let areaCirc=("scale=2;3.1416 * ($radius * $radius)"|bc)
echo "Area of the circle is: " $areaCirc
and the error message is:
syntax error near unexpected token '|'
can someone help me?
To send a string to a command via stdin, use a here-string command <<< string, not a pipe.
Command substitution syntax is $(...), not (...).
Don't use let here. Shell arithmetic only supports integers.
areaCirc=$(bc <<< "scale=2;3.1416 * ($radius * $radius)")
let provides arithmetic context, but we have an ambiguity here, because in a let expression, the vertical bar (|) means bitwise or, but in the shell it has also the meaning of a pipe operator. Look at the following examples:
let bc=4
let a=(4+bc) # Sets a to 8
let b=("5+bc") # Sets b to 9
let c=("(2+4)|bc")
This is syntactically correct and sets c to 6 (because 2+4 equals 6, and the bitwise or of 6 and 4 equals 6).
However if we decided to quote only part of the argument, i.e.
let c=("(2+4)"|bc)
or don't quote at all, i.e.
let c=((2+4)|bc)
we get a syntax error. The reason is that the shell, when parsing a command, first separates it into the different commands, which then are strung together. The pipe is such an operator, and the shell thinks that you want to do a let areaCirc=("scale=2;3.1416 * ($radius * $radius)" and pipe the result into bc. As you can see, the let statement is uncomplete; hence the syntax error.
Aside from this, even if you would fix it, your using of let would not work, because you are using a fractional number (3.1416), and let can do only integer arithmetic. As a workaround, either you do the whole calculation using bc, or some other language (awk, perl,...), or, if this is an option, you switch from bash to zsh, where you can do floating point arithmetic in the shell.

Bash, need to count variables, round to 2 and store to variable [duplicate]

This question already has answers here:
Round a divided number in Bash
(10 answers)
How to display number to two decimal places in bash function
(4 answers)
Closed 3 years ago.
I need to count variables, round to 2 and store to variable.
Example:
I have variable from array ${array[5]} and vat variable defined, I need to calculate simple
( $vat * ${array[5]} + ${array[5]} )
and store to variable pricevat.
I tried:
vat = 0.21
pricevat=$(echo "$vat * ${array[5]}" + ${array[5]} | bc -l)
(( pricevat=$vat*${array[5]}+${array[5]}))
But nothing works:
line 48: ((: pricevat=0.21*0.233+0.233: syntax error: invalid arithmetic operator (error token is ".21*0.233+0.233"
Could you help me please? Where is the problem? What is best solution for this. Thank you very much.
S.
On possibility (though, it will not round, but truncate to 3 decimal places):
array=( ... ... ... ... ... 102.03 ... )
vat=0.21
pricevat=$(bc <<< "scale=3; (1+$vat)*${array[5]}")
The trick is to have bc do the rounding, using its special variable scale, set to 3.
Yes, it is working! I did it like this.
Arithmetic operations:
pricevat=$(echo "$vat * ${array[5]}" + ${array[5]} | bc -l)
Round to 3 places:
pricevat=$(printf "%0.3f\n" $pricevat)
If there is another way to do it better or together on one line, let me know please.
Thanks.

[] reduce with anonymous function in Perl 6

We can use reduce with a sub with two arguments, putting it in double brackets:
> sub mysum { $^a + $^b }
> [[&mysum]] 1,3,5
9
But what if we want to use an anonymous function instead?
Both following variants produce a compile error:
> [[&{ $^a + $^b }]] 1,3,5
> [[{ $^a + $^b }]] 1,3,5
You are not allowed to have any spaces in that form of reduce.
> [[&({$^a+$^b})]] 1, 3, 5
9
This is so that it is more obvious that it is a reduce, and not an array declaration.
> [ { $^a + $^b }, { $^a * $^b } ].pick.(3,5)
8 | 15
The double [[…]] is just an extension of allowing any function to be used as an infix operator.
Note that you must use &(…) in this feature, when not talking about a named function &foo, or an already existing infix operator.
> 3 [&( { $^a + $^b } )] 5
8
This is sort-of an extension of using […] for bracketing meta operators like Z and =
> #a [Z[[+]=]] 1..5
> #a Z[[+]=] 1..5
> #a Z[+=] 1..5
> #a Z+= 1..5
Not sure why that doesn't work. But there's always:
say reduce { $^a + $^b }, 1,3,5 # 9
I'm guessing you knew that but it's all I've got for tonight. :)
I've now moved my comment here and expanded it a bit before I go to sleep.
The TTIAR error means it fails to parse the reduce as a reduce. So I decided to take a quick gander at the Perl 6 grammar.
I searched for "reduce" and quickly deduced that it must be failing to match this regex.
While that regex might be only 20 or so lines long, and I recognize most of the constructs, it's clearly not trivial. I imagine there's a way to use Grammar::Debugger and/or some other grammar debugging tool with the Perl 6 grammar but I don't know it. In the meantime, you must be a bit of a regex whiz by now, so you tell me: why doesn't it match? :)
Update
With Brad's answer to your question as our guide, the answer to my question is instantly obvious. The first line of the regex proper (after the two variable declarations) directly corresponds to the "no spaces" rule that Brad revealed:
<?before '['\S+']'>
This is an assertion that the regex engine is positioned immediately before a string that's of the form [...] where the ... is one or more non-space characters. (\s means space, \S means non-space.)
(Of course, I'd have been utterly baffled why this non-space rule was there without Brad's answer.)

What does the dot mean in this line of code: 65.+rand(10)

I came across this line of code and could not understand the purposed of the dot. Could someone explain what the dot in 65 . + rand(10) is doing and how this is different from 65 + rand(10)?
For full context I saw this code within this 8 char random string generator:
(0...8).map{65.+(rand(25)).chr}.join => "QSILUSPP"
(0...8).map{65.+(rand(25)).chr}.join => "BJIIBQEE"
(0...8).map{65.+(rand(25)).chr}.join => "XORWVKDV"
You can notice, that in original code there are 2 method calls - + and chr. I can show it by equivalent code:
65.send(:+, rand(10)).send(:chr) # is the equal to following line:
65.+(rand(10)).chr
This trick produces method chain, that allows to skip parentheses. With parentheses, 65.+(rand(10)).chr could be written like this:
(65 + rand(10)).chr
Without this trick, chr will apply on rand(10) and the result string will try to be added to 65. It'll produce TypeError:
65+(rand(25)).chr
TypeError: String can't be coerced into Fixnum
It is not any different. As numbers are objects in Ruby, + is actually a method call and can therefore be using the dot syntax like any other method. The form you're used to seeing, 65 + rand(10), is "syntax sugar" and is equivalent to 65.+(rand(10)).
Why anyone would write code using .+, I have no idea.

Ruby Parenthesis syntax exception with i++ ++i

Why does this throw a syntax error? I would expect it to be the other way around...
>> foo = 5
>> foo = foo++ + ++foo
=> 10 // also I would expect 12...
>> foo = (foo++) + (++foo)
SyntaxError: <main>:74: syntax error, unexpected ')'
foo = (foo++) + (++foo)
^
<main>:75: syntax error, unexpected keyword_end, expecting ')'
Tried it with tryruby.org which uses Ruby 1.9.2.
In C# (.NET 3.5) this works fine and it yields another result:
var num = 5;
var foo = num;
foo = (foo++) + (++foo);
System.Diagnostics.Debug.WriteLine(foo); // 12
I guess this is a question of operator priority? Can anybody explain?
For completeness...
C returns 10
Java returns 12
There's no ++ operator in Ruby. Ruby is taking your foo++ + ++foo and taking the first of those plus signs as a binary addition operator, and the rest as unary positive operators on the second foo.
So you are asking Ruby to add 5 and (plus plus plus plus) 5, which is 5, hence the result of 10.
When you add the parentheses, Ruby is looking for a second operand (for the binary addition) before the first closing parenthesis, and complaining because it doesn't find one.
Where did you get the idea that Ruby supported a C-style ++ operator to begin with? Throw that book away.
Ruby does not support this syntax. Use i+=1 instead.
As #Dylan mentioned, Ruby is reading your code as foo + (+(+(+(+foo)))). Basically it's reading all the + signs (after the first one) as marking the integer positive.
Ruby does not have a ++ operator. In your example it just adds the second foo, "consuming" one plus, and treats the other ones as unary + operators.

Resources