Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Can awk interpret algebraic fields?

85 views
Skip to first unread message

Poutounet

unread,
Apr 19, 2011, 9:03:17 AM4/19/11
to
Hello,

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

Kenny McCormack

unread,
Apr 19, 2011, 9:39:07 AM4/19/11
to

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 -

John DuBois

unread,
Apr 19, 2011, 12:42:25 PM4/19/11
to
In article <iok16f$j4e$1...@speranza.aioe.org>, Poutounet <Pou...@net.com> wrote:

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/

Poutounet

unread,
Apr 22, 2011, 5:36:14 AM4/22/11
to

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

Janis Papanagnou

unread,
Apr 22, 2011, 8:55:31 AM4/22/11
to

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

vgersh99

unread,
Mar 27, 2013, 6:13:34 PM3/27/13
to
On Tuesday, April 19, 2011 12:42:25 PM UTC-4, John DuBois wrote:
[snip-snap]
>
> 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/

Very useful util. I was able to do simple things, but what I'm after is an expression like that "$8>200", I get:
!Expected a number; got: $8

The way I call it (in a simplified way):
###
thr=200
params["thr"]=thr
print eval("$8>thr", params)
###
Obviously '$8' is the eighth field on a current line/record.

What am I missing?
Thanks

pop

unread,
Mar 27, 2013, 6:39:33 PM3/27/13
to
vgersh99 said the following on 3/27/2013 5:13 PM:
> eval("$8>thr", params)
try:
eval($8">thr", params)

Hope I understand what you want.

--
pop->Mark

vgersh99

unread,
Mar 27, 2013, 6:49:05 PM3/27/13
to
yep, that works - thanks.
Although (in reality) I can/will have more elaborate expressions, e.g. $8+$5-$3>200
Need to think it over if there're any alternatives to breaking up the expressions in to chunks to have $N evaluated prior to 'eval'.
Ideas?

pop

unread,
Mar 28, 2013, 7:40:27 AM3/28/13
to
vgersh99 said the following on 3/27/2013 5:49 PM:
It sounds like you need to build the strings with the operators inside
the quotes and the variables outside such as:

eval("("$8"+"$5"-"$3")>"200)

parens added to be what I think you want; i.e. not $8+$5-($3>200)
although + and - has precedence over > it makes it clear. Also note that
the constant 200 can inside or outside the quotes. The params argument
would not be needed unless you wish to set some of the options of eval;
you could also build up the string expression into a variable:

x="("$8"+"$5"-"$3")>200"
print eval(x)

I am sure your problem must be a little more complex since all these
examples can be evaluated directly since print ($8+$5-$3)>200 would give
the same result as the eval. However, reading an expression from a file
would make eval necessary.

HTH

--
pop->Mark

0 new messages