I have a file with algebraic expressions as fields. I would like awk to interpret them (i.e.,
compute the results with specific values for each of the variables the expression contains).
I tried the following example (in a unix-like shell):
echo "5.*a" | awk -v a=2 '{print 0+$1}'
but I get "5" as a result because awk only retains "5." and considers the rest as non-number
characters (as far as I understand how it works).
Is it possible to have awk compute the algebraic expression and return 10, which is what I expect?
Thanks in advance for any advice,
Poutounet
The canonical answer is: No, AWK doesn't do that. (With a snide "If you
want Perl, you know where to find it..." thrown in for good measure)
Comments:
1) If you like, you can implement it yourself. Code to evaluate
expressions is pretty easy to write (at least for simple expressions)
and it shouldn't be too hard to find code on the net for it. Of course,
this won't give you access to AWK's own internal state, only to the
state of the language that you implement in (on top of) AWK.
2) FWIW, even the almighty TAWK doesn't have "eval" (like Perl does). Kind
of a shame, actually. TAWK does have _some_ "reflective" functionality,
but it doesn't give you the whole show - and I've never had much luck in
getting them to do anything useful.
--
Faced with the choice between changing one's mind and proving that there is
no need to do so, almost everyone gets busy on the proof.
- John Kenneth Galbraith -
You could use this library:
ftp://ftp.armory.com/pub/lib/awk/eval
Example:
echo "5.*a" | gawk -v a=2 -f eval --source '
BEGIN {
params["a"] = a
}
{
print eval($0, params)
}
'
This prints "10".
If your awk doesn't support the use of both a file and command line as program
source, you can include eval in the main program source.
John
--
John DuBois spc...@armory.com KC6QKZ/AE http://www.armory.com/~spcecdt/
Thanks Kenny and John for your helpful answers.
In the meanwhile, I also tried to have awk write the expressions in an awk program, and then run awk
again with that program, which gives something like this:
echo "5.*a" | awk -v a=2 'BEGIN{print "{a="a";"} {print " print "$0";"} END{print "}"}' > tmp.awk
echo "" | awk -f tmp.awk
The code is ugly, but it is efficient when expressions are much more complex than in this example.
Cheers,
Poutounet
You don't need to feed and empty string into the second awk invocation
if you create in the first awk code an awk BEGIN block instead. I mean
something like
echo "5.*a" |
awk -v a=2 'BEGIN { print "BEGIN {a=" a }
{ print " print " $0 }
END { print "}" }
' > tmp.awk
awk -f tmp.awk
(Though I really wouldn't choose that approach.)
>
> The code is ugly, but it is efficient when expressions are much more complex
> than in this example.
But wouldn't it then be better to stay within shell and do it there?
In shell you have also eval (if you need that), and a modern shell
might support real number arithmetic sufficiently well. Or create
the expressions using some tool like awk, or shell's here-documents,
in case you need some template mechanism, and feed the output into
a calculator like bc.
Janis
>
> Cheers,
> Poutounet