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

coerce arithmetic in variable

2 views
Skip to first unread message

Kim Goldsworthy

unread,
Dec 29, 1999, 3:00:00 AM12/29/99
to
I need to coerce an arithmetic expresssion that is captured in a
variable to have the addition/subtraction/multiplication executed.
---
I have an awk script that parses for numbers in brackets, separated by commas.
Two examples :
[1,16] and [340,340]
In the above, my variables N1 and N2 are:
1 and 16; and 340 and 340.
That's fine, in 98% of my cases.
But sometimes the numbers are offsets, and therefore are arithmetic calculations.
For Example :
[X1*3+4,X1*3+6]
I run my script.
My N1 and N2 are what I want.
e.g., print N1
...returns value:
X1*3+4
So the Question:
What do I do to make awk execute the arithmetic inside my variable?
I want it to calculate and get "4" out of the above example.
---
My attemps so far:
I have the books "sed and awk" and "The awk Programming Language".
They said to add plus zero ( + 0 ) to the assignment.
I tried it, but it returned zero.
That is:
N1 = N1 + 0
and even
N1 = 0 + N1
...returned "0" instead of "4" for the characters in my variable,
namely, X1 * 3 + 4
(since X1 would be undefined to the awk script, and then, times three,
equals zero, plus four)
I ran "gsub" on it to put spaces between the "+" and "*" and stuff, to
see if awk needed separate fields.
No change.
So, what's the secret?
[using SCO Unix, nawk]
---
Kim Goldsworthy


Harlan Grove

unread,
Dec 29, 1999, 3:00:00 AM12/29/99
to
Kim Goldsworthy <geb...@earthlink.net> wrote in message
news:386ADCD7...@earthlink.net...
...

> I have an awk script that parses for numbers in brackets, separated by
commas.
> Two examples :
> [1,16] and [340,340]
> In the above, my variables N1 and N2 are:
> 1 and 16; and 340 and 340.
> That's fine, in 98% of my cases.
> But sometimes the numbers are offsets, and therefore are arithmetic
calculations.
> For Example :
> [X1*3+4,X1*3+6]
...

> What do I do to make awk execute the arithmetic inside my variable?
> I want it to calculate and get "4" out of the above example.
...

> N1 = N1 + 0
> and even
> N1 = 0 + N1
> ...returned "0" instead of "4" for the characters in my variable,
> namely, X1 * 3 + 4
> (since X1 would be undefined to the awk script, and then, times three,
> equals zero, plus four)
...

Which would be more accurate: ignore everything to the left of the rightmost
'+' or evaluate the expression with all non-numeric tokens equal to 0?


If the former, easy:

if (match(N1, /\+ *[0-9]+$/) > 0) N1 = substr(N1, RSTART + 1) + 0


If the latter, you could try the kludge

cmd = "awk 'BEGIN{print " N1 ";exit}'"
cmd | getline N1
close(cmd)

PEZ

unread,
Dec 30, 1999, 3:00:00 AM12/30/99
to
In article <386ADCD7...@earthlink.net>,

Kim Goldsworthy <geb...@earthlink.net> wrote:
> I need to coerce an arithmetic expresssion that is captured in a
> variable to have the addition/subtraction/multiplication executed.

The key word here is "execute". What you need is the equivalent to
the "eval" operator/function present in many other languages. But awk
does not have such a creature. At least not standard awk, which is what
you have as default on SCO systems.

> I have an awk script that parses for numbers in brackets, separated
by commas.
> Two examples :
> [1,16] and [340,340]
> In the above, my variables N1 and N2 are:
> 1 and 16; and 340 and 340.
> That's fine, in 98% of my cases.
> But sometimes the numbers are offsets, and therefore are arithmetic
calculations.
> For Example :
> [X1*3+4,X1*3+6]

> I run my script.
> My N1 and N2 are what I want.
> e.g., print N1
> ...returns value:
> X1*3+4
> So the Question:

> What do I do to make awk execute the arithmetic inside my variable?
> I want it to calculate and get "4" out of the above example.

You could preprocess your datafile (here's an example file):

[2,3][4,5]
[X1+3*4,1][3,Y2+88]
[X1-7,Y1*89][X2+56,Y2-8]

... with a Perl script somewhat like the following:

#!/bin/perl
$Y1=2;
while (<>) {
s/\b([A-Za-z])/\$$1/g;
s/([^],[:space:]\n[]+)/$1/eeg;
print;
}

Short explanation:
1) I only added the $Y=2 there to show that you very well could have
values for these variables when the script starts.
2) The first substitution aims to add a $ sign in front of any letter
at the start of a word (\b matches a word boundary). Since in Perl you
represent scalar variables with a prepended $.
3) The second subtitution changes a string of non squarebrackets, non
white-space, non commas, non newlines with that very string evaluated.
That's what the two e's do there. The first e is to evaluate $1 to the
string it holds and the other e is to evaluate that string.

There are many other ways to do it in Perl. I'm not sure this example
is bullet proof. But with clean input I think it's pretty usuable as is.

Note that you could use another (or the same) input file to initialize
your variables lets say you have a file init.dat that holds the
following line:

[X1=17,Y1-=3][X2=2,Y2=8]

Then you could call the script like so:

the_script init.dat main.dat | tail +2

Of course you could also consider using a2p (which comes with the Perl
distribution) on your awk script to connvert it to a perl script and
apply something like the above script inside it.

> My attemps so far:
> I have the books "sed and awk" and "The awk Programming Language".
> They said to add plus zero ( + 0 ) to the assignment.
> I tried it, but it returned zero.

Adding a zero to a variable in awk only helps (or forces) awk to treat
the variables as a number in contexts where this is not crystal clear.
It doesn't make awk evaluate expressions all of a sudden.

HTH,
/Peter
--
-= Spam safe(?) e-mail address: pez68 at netscape.net =-


Sent via Deja.com http://www.deja.com/
Before you buy.

Harlan Grove

unread,
Dec 30, 1999, 3:00:00 AM12/30/99
to
In article <84fb2a$aqd$1...@nnrp1.deja.com>,

PEZ <pe...@my-deja.com> wrote:
> In article <386ADCD7...@earthlink.net>,
> Kim Goldsworthy <geb...@earthlink.net> wrote:
> > I need to coerce an arithmetic expresssion that is captured in a
> > variable to have the addition/subtraction/multiplication executed.
...

> You could preprocess your datafile (here's an example file):
...

> ... with a Perl script somewhat like the following:

In this case, perl would be a better tool than awk precisely because
the input contains expressions that need to be evaluated. FWIW, the
last sections of TAPL chapter 6 contain code that could be used to
implement fairly complete eval functionality in awk.

That said, offering perl solutions in comp.lang.awk is a bit like
answering the question "What's the French word for 'book'?" with "Well
in German it's 'Buch'."

PEZ

unread,
Dec 30, 1999, 3:00:00 AM12/30/99
to
In article <84gmh7$937$1...@nnrp1.deja.com>,

Harlan Grove <Hrl...@aol.com> wrote:
> In article <84fb2a$aqd$1...@nnrp1.deja.com>,
> PEZ <pe...@my-deja.com> wrote:
> > In article <386ADCD7...@earthlink.net>,
> > Kim Goldsworthy <geb...@earthlink.net> wrote:
> > > I need to coerce an arithmetic expresssion that is captured in a
> > > variable to have the addition/subtraction/multiplication executed.

> > ... with a Perl script somewhat like the following:

> In this case, perl would be a better tool than awk precisely because
> the input contains expressions that need to be evaluated. FWIW, the
> last sections of TAPL chapter 6 contain code that could be used to
> implement fairly complete eval functionality in awk.
>
> That said, offering perl solutions in comp.lang.awk is a bit like
> answering the question "What's the French word for 'book'?" with "Well
> in German it's 'Buch'."

No way. German doesn't compare to French like Perl does to awk. It's
more like comparing German/Swedish/French/English to dogs barking.
(Their word for 'book' is 'waf!", much like many responses to Perl
suggestions in this newsgroup.) Anyway, I just tried to help the dude
getting his job done. Preprocessing the file with some other tool is
his best option since he needs to evaluate those expressions. (If he's
tied to awk that is. Otherwise I guess his best option is to choose
Perl over awk.) But maybe helping each other is a bad thing?

/Peter
--
-= Spam safe(?) e-mail address: pez68 at netscape.net =-

Kenny McCormack

unread,
Dec 30, 1999, 3:00:00 AM12/30/99
to
In article <84gmh7$937$1...@nnrp1.deja.com>,
Harlan Grove <Hrl...@aol.com> wrote:
>FWIW, the last sections of TAPL chapter 6 contain code that could be
>used to implement fairly complete eval functionality in awk.

I'd love to get my hands on that. Any chance it is available on the net?
(Not likely, but can't hurt to ask) I could buy the book and type it in, I
suppose, but it seems so wasteful to re-type it.

>That said, offering perl solutions in comp.lang.awk is a bit like
>answering the question "What's the French word for 'book'?" with "Well
>in German it's 'Buch'."

Good one! In fact, an even better way to phrase it would be "I want to
buy a book in French - what should I do?" and being told "Move to
Germany and ask for a 'Buch'."

Kenny McCormack

unread,
Dec 30, 1999, 3:00:00 AM12/30/99
to
In article <84gos5$aso$1...@nnrp1.deja.com>, PEZ <pe...@my-deja.com> wrote:
>In article <84gmh7$937$1...@nnrp1.deja.com>,
...

>No way. German doesn't compare to French like Perl does to awk. It's
>more like comparing German/Swedish/French/English to dogs barking.
>(Their word for 'book' is 'waf!", much like many responses to Perl

Do you get the impression that Peter would be more happy in a Perl
newsgroup? It's not like there is any shortage of them - in fact, there
are almost as many perl newsgroups as there are trek newsgroups (*)
and, I'd wager, they would tend to be inhabited by about the same kinds of
people.

(*) Actually, I lied. I just checked my newsserver, and there are 81 (!)
trek groups and (only) 32 perl groups. My bad...

Patrick TJ McPhee

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <84gmh7$937$1...@nnrp1.deja.com>,
Harlan Grove <Hrl...@aol.com> wrote:

% That said, offering perl solutions in comp.lang.awk is a bit like
% answering the question "What's the French word for 'book'?" with "Well
% in German it's 'Buch'."

However, the word for 'novel' is the same in both languages (Roman).
Also, concrete has the same word (beton) in several languages. Perhaps
we should talk about novels and concrete, rather than books? Did you ever
consider that?

One approach to the original problem which falls short of either writing an
expression parser or changing languages is to invoke awk using getline.

Given variables X1, X2, Y1, and Y2, where X1 and Y1 are known to always
be constant values and X2 and Y2 are sometimes arithmetic expressions
involving X1 and Y1, you can have:
...

if (is_expression(X2)) X2 = eval_expression(X2, X1, Y1)
if (is_expression(Y2)) Y2 = eval_expression(Y2, X1, Y1)

...


function is_expression(EXP)
{
return EXP !~ /^[0-9]+$/
}

function eval_expression(EXP, X1, Y1)
{
cmd = "awk -v X1=" X1 " -v Y1=" Y1 " 'BEGIN { print " EXP "}'"
cmd | getline EXP
close(cmd)
return EXP
}

This might sound dreadful, but you put the expression functions in
another file and include it with -f, and nobody has to know.

--

Patrick TJ McPhee
East York Canada
pt...@interlog.com

Jim Monty

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
Kenny McCormack <gaz...@interaccess.com> wrote:
> Harlan Grove <Hrl...@aol.com> wrote:
> > FWIW, the last sections of TAPL chapter 6 contain code that could be
> > used to implement fairly complete eval functionality in awk.
>
> I'd love to get my hands on that. Any chance it is available on the net?
> (Not likely, but can't hurt to ask)

http://cm.bell-labs.com/cm/cs/who/bwk/awkcode.txt
http://cm.bell-labs.com/cm/cs/who/bwk/awkcode.zip

> I could buy the book and type it in, I suppose, but it seems so
> wasteful to re-type it.

You really should own the book.

--
Jim Monty
mo...@primenet.com
Tempe, Arizona USA

gebegb

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <386ADCD7...@earthlink.net>,
Kim Goldsworthy <geb...@earthlink.net> wrote:
> I need to coerce an arithmetic expresssion that is captured in a variable...
---
I thank you all for replying.
Even the Piss Wars don't bother me (much).

(I did not know that you kept the "subject" line as is, when discussing
translations for "book"; live and learn, no?)

You all are RegEx gods, in my book. Well... Posix Daemons, at least... ---
Here's an update: My SCO box does not have perl. (Another SCO box for another
department is using perl, lucky them; I requested that we get a perl for our
box; no reply to date.) So I could rewrite my awk script in Korn Shell if you
guys think "eval" and "expr" and (( )) will do what I want. (i.e., take an
arithmetic expression inside a variable and calculate a value.)

Wuddya say???
---
-Kim Goldsworthy

PEZ

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <B9Va4.34$FW....@cac1.rdr.news.psi.ca>,

It seems perfectly sound to me. But if there are many calls to
eval_expression I think maybe it will both waste resources and be time
consuming. At least it is a workable solution that might be of help to
the original poster.

/Peter
--
-= Spam safe(?) e-mail address: pez68 at netscape.net =-

PEZ

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <84gt58$2ok$1...@yin.interaccess.com>,

gaz...@interaccess.com wrote:
> In article <84gmh7$937$1...@nnrp1.deja.com>,
> Harlan Grove <Hrl...@aol.com> wrote:
> >That said, offering perl solutions in comp.lang.awk is a bit like
> >answering the question "What's the French word for 'book'?"
with "Well
> >in German it's 'Buch'."
>
> Good one! In fact, an even better way to phrase it would be "I want
to
> buy a book in French - what should I do?" and being told "Move to
> Germany and ask for a 'Buch'."

No it's a really lousy analoy. It sounds as good as "my God is better
than your God". A better analogy would be: To tell someone that ask how
to get these screws into the wall using a hammer to instead try with a
screwdriver. Even if you don't sell screwdrivers you have helped your
customer better than if you had told him to buy your Hammer 2000 and
just bang the screws in like they were nails. Or to melt the hammer
down and mold a screwdriver-like thingy from it.

PEZ

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <84hgff$qkn$1...@nnrp1.deja.com>,

gebegb <geb...@my-deja.com> wrote:
> In article <386ADCD7...@earthlink.net>,
> Kim Goldsworthy <geb...@earthlink.net> wrote:
> Here's an update: My SCO box does not have perl. (Another SCO box for
another
> department is using perl, lucky them; I requested that we get a perl
for our
> box; no reply to date.) So I could rewrite my awk script in Korn
Shell if you
> guys think "eval" and "expr" and (( )) will do what I want. (i.e.,
take an
> arithmetic expression inside a variable and calculate a value.)

Ummm, maybe. But I think it might be a bit of a bother using ksh. Well
maybe you could do something like use awk (or sed) to change your file
to a syntax of valid ksh code then eval that code. I don't have the
time to test it right now (on my way to a millennium party, the time is
ticking here). Something like this:

awk 'gsub(/\[/, "[$(("); gsub(/,/, ")),$(("); gsub(/]/, "))]"); print' |
while read EXPR
do
RESULT=eval $EXPR
print "$RESULT"
done

Ehhh, well it's completely untested but I think it might be possible to
make it work.

You have already got two suggestions on using a sub-awk process to
evaluate the stuff. Those should work as well, although with much more
overhead I think.

HTH,

PEZ

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <84ih8e$fmc$1...@nnrp1.deja.com>,

PEZ <pe...@my-deja.com> wrote:
> In article <84hgff$qkn$1...@nnrp1.deja.com>,
> gebegb <geb...@my-deja.com> wrote:
> > In article <386ADCD7...@earthlink.net>,
> > Kim Goldsworthy <geb...@earthlink.net> wrote:
> > Here's an update: My SCO box does not have perl. (Another SCO box
for
> another
> > department is using perl, lucky them; I requested that we get a perl
> for our
> > box; no reply to date.) So I could rewrite my awk script in Korn
> Shell if you
> > guys think "eval" and "expr" and (( )) will do what I want. (i.e.,
> take an
> > arithmetic expression inside a variable and calculate a value.)
>
> Ummm, maybe. But I think it might be a bit of a bother using ksh. Well
> maybe you could do something like use awk (or sed) to change your file
> to a syntax of valid ksh code then eval that code. I don't have the
> time to test it right now (on my way to a millennium party, the time
is
> ticking here). Something like this:

Well, party is over. Now I'm preparing myself for a long exciting night
with the puters here at work to make sure they roll over safely into
the next millennium.

> awk 'gsub(/\[/, "[$(("); gsub(/,/, ")),$(("); gsub(/]/, "))]");
print' |
> while read EXPR
> do
> RESULT=eval $EXPR
> print "$RESULT"
> done
>
> Ehhh, well it's completely untested but I think it might be possible
to
> make it work.

Completely untested and buggy as hell. And not really that simple. But
I have ironed out the most obvious bugs and made added the complexity
to make it work. Like so:

#!/usr/bin/ksh
typeset Y2=4
awk '
{
gsub(/[A-Za-z]+[A-Za-z0-9]*/, "${&-0}")


gsub(/\[/, "[$((")
gsub(/,/, ")),$((")
gsub(/]/, "))]")
print

}' $* | while read EXPR
do
eval "print $EXPR"
done

Again you can of course initiate the variables before the script. I
wouldn't do it inside the script like above. Since it's the shell you
could export the variables before calling the script.

Let me know if it works or not for you Kim,

Harlan Grove

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <84ig9l$f49$1...@nnrp1.deja.com>, PEZ <pe...@my-deja.com> writes:

<snip>

>No it's a really lousy analoy. It sounds as good as "my God is better
>than your God". A better analogy would be: To tell someone that ask how
>to get these screws into the wall using a hammer to instead try with a
>screwdriver. Even if you don't sell screwdrivers you have helped your
>customer better than if you had told him to buy your Hammer 2000 and
>just bang the screws in like they were nails. Or to melt the hammer
>down and mold a screwdriver-like thingy from it.

Depends on whether you have a screwdriver (perl isn't a standard component of
most operating systems, awk is on unix systems). If not, and you need to drive
screws into the wall _now_, getting advice to make a trip to the hardware store
or take up forging isn't necessarily best advice.

Anyway, I made a crude attempt at trivial expression parser and Patrick McPhee
did a much better job. There's a third possibility (harder): use awk as the
preprocessor. The awk preprocessor would read the 'data' file, write any
expressions found in this file to a new awk script file in the form

BEGIN { preproc = "./tmp_awk_preproc"; print "function eval_expr( e) {" >
preproc }
if (find_expressions()) {
printf("\tif (FILENAME == \"%s\" && FNR == %d) {", FILENAME, FNR) > preproc
for (e = 1; e < expression_count; ++e) printf("\t\t%s\n", expression_[e]) >
preproc
print "\t" > preproc
}
END { print "}" > preproc; close(preproc) }
function find_expressions(...) {...} # this is the hard part - see TAPL chapter
6

So preprocessing is a reasonable path to take, but it doesn't _necessarily_
have to be done in perl; it could be done in awk. Perl's advantage is that
preprocessing isn't necessary. Perl's eval could handle expression evaluation
within the main script. FWIW, mks awk would allow inline expression evaluation
(assuming you code the eval function) since it includes a SYMTAB variable which
provides access to all awk variables.

Next question: if someone wanted a perl solution to a particular problem, why
would he/she post to comp.lang.awk rather than comp.lang.perl.misc?

Kenny McCormack

unread,
Dec 31, 1999, 3:00:00 AM12/31/99
to
In article <84jkua$73k$1...@nnrp1.deja.com>, PEZ <pe...@my-deja.com> wrote:
>In article <19991231185131...@nso-fx.aol.com>,
...

>> Next question: if someone wanted a perl solution to a particular
>>problem, why would he/she post to comp.lang.awk rather than
>>comp.lang.perl.misc?

I think the point is made that both perl-solution-seekers and
perl-solution-givers will have better luck peddling their wares in perl
groups. (I don't think this observation is rocket science)

>I assumed he wanted a solution to the problem. Why would it matter
>if it happened to use another tool? It was a preprocessing approach
>_because_ awk isn't close to ideal for the particular problem. I really
>totally and utterly fail to see what can be so bad about trying to
>provide help. But maybe that's just because I'm solution oriented to my
>nature. Not tool oriented.

Well, following your logic, even better advice would be to get somebody else
to do it for you (that's the way managers solve problems).


PEZ

unread,
Jan 1, 2000, 3:00:00 AM1/1/00
to
In article <19991231185131...@nso-fx.aol.com>,

hrl...@aol.comzzzzzz (Harlan Grove) wrote:
> In article <84ig9l$f49$1...@nnrp1.deja.com>, PEZ <pe...@my-deja.com>
writes:
> Anyway, I made a crude attempt at trivial expression parser and
Patrick McPhee
> did a much better job.

The problem with those attempts as I see it is that they start an
instance of awk for each expression that needs to be evaluated. But
it's a possibility yes.

> So preprocessing is a reasonable path to take, but it doesn't
_necessarily_
> have to be done in perl; it could be done in awk. Perl's advantage is
that
> preprocessing isn't necessary. Perl's eval could handle expression
evaluation

No one (at least not I) said it had to be done in Perl. My point was
that it was better to use a tool with eval functionality built in. I
provided a Perl script just because I knew how to and it was very
straight forward.

> within the main script. FWIW, mks awk would allow inline expression
evaluation
> (assuming you code the eval function) since it includes a SYMTAB
variable which
> provides access to all awk variables.

Well, the eval function is the real meat here. Access to awk variables
are not necessary to do the job. You could easily fake that using your
own symbol table.

> Next question: if someone wanted a perl solution to a particular
problem, why
> would he/she post to comp.lang.awk rather than comp.lang.perl.misc?

I assumed he wanted a solution to the problem. Why would it matter if


it happened to use another tool? It was a preprocessing approach
_because_ awk isn't close to ideal for the particular problem. I really
totally and utterly fail to see what can be so bad about trying to
provide help. But maybe that's just because I'm solution oriented to my
nature. Not tool oriented.

It's two and a half hour into the new millenium here. Cool. And all
"my" servers are behaving.

Happy New Year!

Charles Demas

unread,
Jan 1, 2000, 3:00:00 AM1/1/00
to
In article <19991231185131...@nso-fx.aol.com>,

Harlan Grove <hrl...@aol.comzzzzzz> wrote:
>
>Next question: if someone wanted a perl solution to a particular problem, why
>would he/she post to comp.lang.awk rather than comp.lang.perl.misc?


Because the people in comp.lang.awk are usually friendlier than the
perl crowd??? :-)


Chuck Demas
Needham, Mass.

--
Eat Healthy | _ _ | Nothing would be done at all,
Stay Fit | @ @ | If a man waited to do it so well,
Die Anyway | v | That no one could find fault with it.
de...@tiac.net | \___/ | http://www.tiac.net/users/demas

Harlan Grove

unread,
Jan 1, 2000, 3:00:00 AM1/1/00
to
In article <FnMyr...@world.std.com>, de...@sunspot.tiac.net (Charles Demas)
writes:

>Because the people in comp.lang.awk are usually friendlier than the
>perl crowd??? :-)

Naaaaaaaa!!!!!

HNY

PEZ

unread,
Jan 1, 2000, 3:00:00 AM1/1/00
to
In article <84jsig$8lh$1...@yin.interaccess.com>,

gaz...@interaccess.com wrote:
> In article <84jkua$73k$1...@nnrp1.deja.com>, PEZ <pe...@my-deja.com>
wrote:
> >I assumed he wanted a solution to the problem. Why would it matter
> >if it happened to use another tool? It was a preprocessing approach
> >_because_ awk isn't close to ideal for the particular problem. I
really
> >totally and utterly fail to see what can be so bad about trying to
> >provide help. But maybe that's just because I'm solution oriented to
my
> >nature. Not tool oriented.
>
> Well, following your logic, even better advice would be to get
somebody else
> to do it for you (that's the way managers solve problems).

OK, maybe that's true. If that's what it takes to get the job done. But
I must ask. Following _your_ logic, what would you do? Is it so far
from mone? Don't you strive to solve problems, get the job done? That
would once and for all explain to me why you dislike Perl.

Kim Goldsworthy

unread,
Jan 2, 2000, 3:00:00 AM1/2/00
to
For those who answered my post, and wished to know the final result--

I wrote my first Function in awk!
Hooray!

I ended up using the combination of:
Function plus Getline!
Just like Patrick and Peter suggested!

I changed the non-numeric parts of the arithmetic to explict zeros.
I used the Korn Shell's (( )) to do the calculation.

(see below)
======
# editor's note: assume variable "myarg" contains formula: X1 * 3 + 4

# --- FUNCTION ---

function RidAlpha(myarg)
{
new = ""
c = split(myarg,array)

for (ele = 1; ele <= c; ele++) {
if (array[ele] ~ "^[A-Z]") { array[ele] = 0 }
new = new array[ele] " "
}

mycmd = "ksh -c \'((x=" new ")) ; print $x\'"
mycmd | getline hey
return hey
}
# --- END FUNCTION ---
====

And I'll have you know, I sweated over this thing.
The big bug was the re-use of a variable.
I was using variable "i" for a FOR loop up front, and using "i" in the
Function, too.
So the bug was looping on the first line forever.
I thought variables in Functions were LOCAL!?!
I had to change variable "i" to "ele" in the Function to halt the conflict.
(Do you know how hard it was to find that bug?--I was asking myself:"Why
is my 'i' now 3 instead of 13?"
But it works.

Don't criticize the simplicy -- I am learning this stuff piecemeal.
It's probably not effecient, and could be shorter.
But I fear touching off another P--- War, about translations of "book",
if I let this thread go on.

Thanks to all.

===

Kim Goldsworthy wrote:
>
> I need to coerce an arithmetic expresssion that is captured in a

Jim Monty

unread,
Jan 2, 2000, 3:00:00 AM1/2/00
to
Kim Goldsworthy <geb...@earthlink.net> wrote:
> ======
> # editor's note: assume variable "myarg" contains formula: X1 * 3 + 4
>
> # --- FUNCTION ---
>
> function RidAlpha(myarg)
> {
> new = ""
> c = split(myarg,array)
>
> for (ele = 1; ele <= c; ele++) {
> if (array[ele] ~ "^[A-Z]") { array[ele] = 0 }
> new = new array[ele] " "
> }
>
> mycmd = "ksh -c \'((x=" new ")) ; print $x\'"
> mycmd | getline hey
> return hey
> }
> # --- END FUNCTION ---
> ====
>
> And I'll have you know, I sweated over this thing.
> The big bug was the re-use of a variable.
> I was using variable "i" for a FOR loop up front, and using "i" in the
> Function, too.
> So the bug was looping on the first line forever.
> I thought variables in Functions were LOCAL!?!

In awk, the only variables that are local to a function are those
in the parameter list of the function definition. All other variables
are global. So to localize a variable, include it in the parameter
list after any function arguments. For example, your function named
RidAlpha might be defined thus:

function RidAlpha(myarg, new, c, array, ele, mycmd, hey) { ... }

The usual convention is to separate the function arguments from
the local variables with several spaces to help distinguish them.
In the example above, the variable myarg is the only one (hopefully!)
that is passed a value when the function is called. The other
variables (new, c, array, etc.) are in the parameter list solely
to limit their scope to the life of the function.

If this seems inelegant to you, you're right: it is. But it's the
best way Messrs. A., W., and K. could think of to allow some level
of user-controlled variable scoping in a language purposefully
devoid of variable declarations.

> I had to change variable "i" to "ele" in the Function to halt the conflict.

Now you know how to change it back.

> Do you know how hard it was to find that bug?

Yes.

PEZ

unread,
Jan 3, 2000, 3:00:00 AM1/3/00
to
In article <386FAD19...@earthlink.net>,

Kim Goldsworthy <geb...@earthlink.net> wrote:
> For those who answered my post, and wished to know the final result--
>
> I wrote my first Function in awk!
> Hooray!

Congrats!

> I ended up using the combination of:
> Function plus Getline!
> Just like Patrick and Peter suggested!

Patrick and Harland I think you mean.

> I changed the non-numeric parts of the arithmetic to explict zeros.
> I used the Korn Shell's (( )) to do the calculation.
>

> # editor's note: assume variable "myarg" contains formula: X1 * 3 + 4
>

> function RidAlpha(myarg)
> {
> new = ""
> c = split(myarg,array)
>
> for (ele = 1; ele <= c; ele++) {
> if (array[ele] ~ "^[A-Z]") { array[ele] = 0 }
> new = new array[ele] " "
> }
>
> mycmd = "ksh -c \'((x=" new ")) ; print $x\'"
> mycmd | getline hey
> return hey
> }
> # --- END FUNCTION ---
> ====

> Don't criticize the simplicy -- I am learning this stuff piecemeal.
> It's probably not effecient, and could be shorter.

I won't criticize. But a few friendly reflections might be appropriate,
no?

Firstly. I would still use my above ksh approach over this one. It only
starts awk and ksh one time each for your entire file. And your main
awk program will be free from the obfuscating and somewhat irrelevant
expression handling and focus can remain on your main task. If you want
all in the same script, my approach can too be incapsulated in a
function which can be called before anything else happens in your
script. But make sure it's called just once for your input file and not
once for each expression. (And by all means add the check "is
expression handling necessary" if you feel that is more efficient.)

Secondly. If you are still going to start a subprocess for each
expression. I would go for Patrick's solution instead. Because that
solution does only involve awk (or at least involves less "shell"
stuff). All you need to do to your function is build an awk command
instead of a ksh command. (Assuming you have already applied Jim's
pointers on how to limit the scope of those local variables.) You don't
even need to replace those variables with zero. If you take Patrick's
full solution you can even have values for those variables.

Thirdly. I think RidAlpha is an unlucky name for a function that does
so much more than just rid its argument of alpha strings (including
introducing the overhead of two shell calls). EvalExpression is better
even if it's a bit crippled by the fact that you exchange all variables
with zero.

Forthly (minor compared to those above). If you still want to replace
those variables with zero. I would do it with a gsub(). It's clearer
and (I think) more efficient. I think 'gsub(/[A-Z][A-Z0-9]*/, "0",
myarg)' would do the job. (You could of course anchor it to the
beginning of the string if that's really what you want. In that case
use sub() instead.) If you don't need to squeeze in those spaces in the
expression for other reasons, you could skip that step in your script
with the gsub() approach.

This one I'm not sure about. But I think you should close("mycmd") when
you are done with it. Maybe some of the others in this newsgroup can
confirm this or shoot it down as not necessary.

> But I fear touching off another P--- War, about translations
of "book",
> if I let this thread go on.

Basil Fawlty: Don't mention the war!
(Actually involves a German fellow, but no French dudes.)

Seriously. Don't fear starting of small wars. This newsgroup is touchy
as hell. You can't say nothing without the war starting anyway, so it's
not worth the bother.

FWIW,

PEZ

unread,
Jan 4, 2000, 3:00:00 AM1/4/00
to
In article <386ADCD7...@earthlink.net>,

Kim Goldsworthy <geb...@earthlink.net> wrote:
> X1*3+4
> So the Question:
> What do I do to make awk execute the arithmetic inside my variable?
> I want it to calculate and get "4" out of the above example.

Well, I have come up with yet another way to do it. This time using
only awk (well, close). This would make the script portable to almost
all platforms where we have awk. It resembles Patrick's solution some.
But this one is meant for preprocessing, which I insist on being
preferrable in the actual case. And it tries to just do the
calculations and leave the rest of the input untouched. Like so:

#!/bin/awk -f
# pp_expr: evaluate any expressions embedded in the data file
# builds an awk script from the input and executes it with system()
# example usage: ./pp_expr -v pp_args='-v Y2=100'
# (pp_args will be passed to the temporary awk script)
BEGIN {
pp_file = ".pp_expr.awk"
print "BEGIN {" > pp_file
}
{
# add to or subtract from the character class to
# change what doesn't counts as part of an expression
gsub(/[ \t]*[^-+*/=)(A-Za-z0-9. \t]+[ \t]*/, "\"&\"")
print "print " $0 > pp_file
}
END {
print "}" > pp_file
close(pp_file)
system("awk -f " pp_file " " pp_args)
# here you can remove the temporary file
}

On the following input:
X1=100


[2,3][4,5]
[X1+3*4,1][3,Y2+88]
[X1-7,Y1*89][X2+56,Y2-8]

This command:
./pp_expr -v pp_args='-v Y2=100'

Produces this:
100
[2,3][4,5]
[112,1][3,188]
[93,0][56,92]

The hole thing could be transformed into a function, but for the
purpose of preprocessing I find that would clutter things. One more
advantage this would have over the ksh equivalent I suggested is that
it can deal with floating point arithmetics as well.

The script is very simple and doesn't handle errors at all (or rather
leaves it up to awk to report errors on the resulting script). It
doesn't preserve leading whitespace. (Something I think could be added
without too much trouble.) The script presents a general approach but
is not in itself generally applicable since the core regular expression
would have to be tuned for each type of input.

0 new messages