Perl Math Syntax

D

\Dandy\ Randy

Hello peoples,

Needs some help getting a ... well ... pretty basic math script working but
the solution eludes me .... I have a text file called opened.txt ... it
contains the following single line data:

2000|0|0

What I am looking to do is when the script is run, I would like the second
value to increase by 1 .... kind of like this:

#!/usr/bin/perl

open (FILE, "<opened.txt") or &error("Unable to open");
$data=<FILE>;
chomp ($data);
($total,$opened,$closed)=split(/\|/,$data);
close(FILE);

$opened = $opened + 1; // is incorrect of course

open (FILE, ">opened.txt") or &error("Unable to open");
print FILE "$total|$opened|$closed";
close(FILE);

print "Content-type: text/html \n\n";
print "All done";
exit;

So now the data in opened.txt would read:

2000|1|0

Can you please help me with the syntax to increase the second value when the
script is run. Thanx!

Randy
 
E

Eric Schwartz

\"Dandy\" Randy said:
Needs some help getting a ... well ... pretty basic math script
working but the solution eludes me .... I have a text file called
opened.txt ... it contains the following single line data:

2000|0|0

What I am looking to do is when the script is run, I would like the second
value to increase by 1 .... kind of like this:

So now the data in opened.txt would read:

2000|1|0

Can you please help me with the syntax to increase the second value
when the script is run. Thanx!

It works fine for me:

emschwar@wormtongue:/tmp$ cat opened.txt
2000|2|0
emschwar@wormtongue:/tmp$ perl test.pl
Content-type: text/html

All doneemschwar@wormtongue:/tmp$ cat opened.txt
2000|3|0emschwar@wormtongue:/tmp$

Btw, some comments on your script:

* You didn't use strict or warnings. That's bad; you should always
ask Perl to help you as much as possible. In this example, anyway,
all it would cost you is a few 'my's.
* You're checking your open()s for failure, which is good, but you
should include $! so you'll know WHY they failed.
* You seem to be writing a CGI program; in that case, you should be
using the CGI module. 'perldoc CGI' for more details.
* Your problem may have to do with multiple users running that code at
once. You really should be performing some sort of lock on the file
before editing it like that. See 'perldoc -q lock' for more
details.
* // is NOT a valid Perl comment. If you have it in your real code,
then that may well be your problem. If you don't, then shame on you
for not posting real live code. :)
* For human-reability, you'll probably want to print a "\n" at the end
of the file after you update it.

-=Eric
 
G

Gunnar Hjalmarsson

Dandy" Randy said:
I have a text file called opened.txt ... it contains the following
single line data:

2000|0|0

Can you please help me with the syntax to increase the second value
when the script is run.

Your code doesn't include any apparent errors. The first thing you
should do - before asking for help here - is asking Perl to help you
find the problem by adding

use strict;
use warnings;

and study possible messages written to STDERR.
 
E

Eric Schwartz

\"Dandy\" Randy said:
Thank you for playing Eric, my comments:

A) I dont know a heck of alot about strict or warnings, but I'l look into
that.

perldoc strict
perldoc warnings
B) Good point about opening files, will modify.
C) Multipul users is od course a bid thing, in which case i would modify my
write-to-file script like so:

open (FILE, ">opened.txt") or &error("Unable to open");
flock FILE, 2;
print FILE "$total|$opened|$closed";
close(FILE);

Just curious, I got this flock code from a perldoc example ... what does the
"2" represent? should it be a different value? Or ... is flocking really
what I need to be doing?

Did you read the perldocs I referred you to? They specifically
contain examples of how to do it right. In fact, I'm not sure which
perldocs you have that suggest using literal numbers, as all the
obvious ones (perldoc -f flock, perldoc -q locking) used Fcntl.pm to
provide the symbolic constants LOCK_EX and LOCK_SH, and so on.

Also, and this is a big one here: do NOT top-post, and do NOT quote
the reply in its entirety. This is rude, and makes things harder to
read than they need to be.

It causes confusion like this.
Why shouldn't you top-post?

Instead, intersperse your comments with the text they're replying to,
and only quote what's necessary to provide the context for your
replies. I'm no paragon of virtue, but observe this reply for an
example.

-=Eric
 
D

\Dandy\ Randy

perldoc strict
perldoc warnings

Gotcha, tnx
Did you read the perldocs I referred you to? They specifically
contain examples of how to do it right. In fact, I'm not sure which
perldocs you have that suggest using literal numbers, as all the
obvious ones (perldoc -f flock, perldoc -q locking) used Fcntl.pm to
provide the symbolic constants LOCK_EX and LOCK_SH, and so on.

I had read the section on flocking in the perdoc located at www.perdoc.com.
After studying further, I would now choose to use the following locking
procedure when writing to file:

use 5.004;
use Fcntl qw:)DEFAULT :flock);
open (FILE, ">opened.txt") or die "Unable to open: $!";
flock (FILE, LOCK_EX) or die "Can't lock file: $!";
print FILE "$total|$opened|$closed";
close(FILE);

Not quite sure what the use 5.004 does as noted in the perdoc but i'll trust
it's needed. There were sections on SH & EX ... any opinions on whether I
should be using shared locks or exclusive locks? At most maybe 10-20 users
may access the opened.txt file at any one time. I assume flocking would add
them to a cue rather than just not allowing access period. Thoughts? thanx
again!

R
 
E

Eric J. Roode

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

$opened = $opened + 1; // is incorrect of course

Please elaborate on why you are drawing the conclusion that this is
incorrect "of course". It's not.

- --
Eric
$_ = reverse sort qw p ekca lre Js reh ts
p, $/.r, map $_.$", qw e p h tona e; print

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>

iQA/AwUBPy8S12PeouIeTNHoEQKtygCgwnqfX+LPlNgp8fHY1ztvPh5ckXwAoNxT
VMb2M0IEMUPEnNr1+97t8SLR
=6OuB
-----END PGP SIGNATURE-----
 
T

Tad McClellan

[ please do not top-post ]


A) I dont know a heck of alot about strict or warnings, but I'l look into
that.


They help you find common mistakes.

They will do it in only a part of one second...

.... or leave them out and spend hundreds/thousands? of seconds
chasing common mistakes.

Your choice.


open (FILE, ">opened.txt") or &error("Unable to open");
flock FILE, 2;
print FILE "$total|$opened|$closed";
close(FILE);

Just curious, I got this flock code from a perldoc example ... what does the
"2" represent?


All of Perl's functions are documented in the perlfunc manual.

You can look up a function's description with the -f switch:

perldoc -f flock

If there was some part of what is said there that you didn't
understand, then tell us what part and we'll help you to
understand it.

should it be a different value?


It _could_ be a different value on different operating systems,
so it is best to use the imported constants instead of hard-coding
a particular number.

perldoc mentions that too...

Or ... is flocking really
what I need to be doing?


Yes, you need file locking when multiple processes may write
to a file at the same time (eg. in a CGI environment).
 
J

John W. Krahn

\"Dandy\" Randy said:
Needs some help getting a ... well ... pretty basic math script working but
the solution eludes me .... I have a text file called opened.txt ... it
contains the following single line data:

2000|0|0

What I am looking to do is when the script is run, I would like the second
value to increase by 1 .... kind of like this:

#!/usr/bin/perl

( $^I, @ARGV ) = ( '', 'opened.txt' );
s/|(\d+)|/|@{[$1+1]}|/ while <>;

__END__



John
 
E

Eric J. Roode

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

It's not incorrect, but the OP is probably better off doing:

$opened++;

Why is that "better"? For a simple variable increment, I would say that
it's just a matter of style. I can't see any real difference between

$opened = $opened + 1;
$opened += 1;
$opened++;

- --
Eric
$_ = reverse sort qw p ekca lre Js reh ts
p, $/.r, map $_.$", qw e p h tona e; print

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>

iQA/AwUBPy+E4WPeouIeTNHoEQICNwCgmWgIJtlKRKtVFWdwd272fgsi7O8AoNsB
XkwWOkdyis8BNwJ+a68+bWVR
=HiK5
-----END PGP SIGNATURE-----
 
T

Tad McClellan

\"Dandy\" Randy said:
print FILE "$total|$opened|$closed";
^^
^^ aren't you missing a \n there?

Not quite sure what the use 5.004 does


Requires perl version 5.004 or newer.

The program will not run if used with an earlier version.

There were sections on SH & EX ... any opinions on whether I
should be using shared locks or exclusive locks?


It is not a matter of "opinion".

It is a matter of which protects against corrupted data and
which doesn't.

Use an exclusive lock when writing to the file.

Use a shared lock when reading from the file.
 
J

John W. Krahn

JS said:
At the behest of another poster, I benchmarked these using the following
code:

------------------
#!/usr/bin/perl

use Benchmark qw(cmpthese);

my ($a, $b, $c) = (0, 0, 0);

cmpthese(10000000, {
Plus => sub { $a = $a + 1 },
PlusEq => sub { $b += 1 },
PlusPlus => sub { $c++ }
});
------------------

The results suprised me quite a bit:

-----------------
Benchmark: timing 10000000 iterations of Plus, PlusEq, PlusPlus...
Plus: 2 wallclock secs ( 1.10 usr + 0.00 sys = 1.10 CPU) @
9090909.09/s (n=10000000)
PlusEq: 2 wallclock secs ( 1.31 usr + 0.00 sys = 1.31 CPU) @
7633587.79/s (n=10000000)
PlusPlus: 2 wallclock secs ( 1.49 usr + 0.00 sys = 1.49 CPU) @
6711409.40/s (n=10000000)
Rate PlusPlus PlusEq Plus
PlusPlus 6711409/s -- -12% -26%
PlusEq 7633588/s 14% -- -16%
Plus 9090909/s 35% 19% --

Interesting. I get somewhat different results (isn't benchmarking fun!)

$ perl -e'
use Benchmark qw/cmpthese/;
cmpthese( -60, {
plus => sub { my $x; $x = $x + 1 while $x < 1000; $x },
plusequals => sub { my $x; $x += 1 while $x < 1000; $x },
preplusplus => sub { my $x; ++$x while $x < 1000; $x },
postplusplus => sub { my $x; $x++ while $x < 1000; $x },
} )'
Benchmark: running plus, plusequals, postplusplus, preplusplus, each for at least 60 CPU seconds...
plus: 69 wallclock secs (62.71 usr + 0.39 sys = 63.10 CPU) @ 450.52/s (n=28428)
plusequals: 65 wallclock secs (63.59 usr + 0.24 sys = 63.83 CPU) @ 451.03/s (n=28789)
postplusplus: 64 wallclock secs (62.41 usr + 0.17 sys = 62.58 CPU) @ 561.57/s (n=35143)
preplusplus: 64 wallclock secs (63.06 usr + 0.08 sys = 63.14 CPU) @ 560.86/s (n=35413)
Rate plus plusequals preplusplus postplusplus
plus 451/s -- -0% -20% -20%
plusequals 451/s 0% -- -20% -20%
preplusplus 561/s 24% 24% -- -0%
postplusplus 562/s 25% 25% 0% --


:)

John
 
S

Steve Grazzini

John W. Krahn said:
Interesting. I get somewhat different results (isn't benchmarking fun!)

preplusplus => sub { my $x; ++$x while $x < 1000; $x },
postplusplus => sub { my $x; $x++ while $x < 1000; $x },

FWIW: post-increment in void context gets "optimized".

% perl -MO=Concise,foo -e 'sub foo { $x++; $x }'
-e syntax OK
main::foo:
6 <1> leavesub[t1] K/REFC,1 ->(end)
- <@> lineseq KP ->6
1 <;> nextstate(main 1 -e:1) v ->2
3 <1> preinc[t2] vK/1 ->4
- <1> ex-rv2sv sKRM/1 ->3
2 <#> gvsv[*x] s ->3
4 <;> nextstate(main 1 -e:1) v ->5
- <1> ex-rv2sv sK/1 ->-
5 <#> gvsv[*x] s ->6
 
E

Eric J. Roode

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

EJR> Why is that "better"? For a simple variable increment, I would
EJR> say that it's just a matter of style. I can't see any real
EJR> difference between

EJR> $opened = $opened + 1;
EJR> $opened += 1;
EJR> $opened++;

run them under the benchmark module. report your results back here.

use Benchmark;
my $o;
timethese (10_000_000,
{
1 => sub { $o = $o + 1 },
2 => sub { $o += 1 },
3 => sub { $o++ },
} );

Result:

Benchmark: timing 10000000 iterations of 1, 2, 3...
1: 2 wallclock secs ( 0.80 usr + 0.01 sys = 0.81 CPU)
@ 12315270.94/s (n=10000000)
2: 4 wallclock secs ( 3.46 usr + 0.00 sys = 3.46 CPU)
@ 2886836.03/s (n=10000000)
3: 2 wallclock secs ( 2.30 usr + 0.00 sys = 2.30 CPU)
@ 4340277.78/s (n=10000000)

Conclusion:
It doesn't make a bit of difference which style one uses. Sure, one
could take the shortsighted view that "$o = $o + 1" is four times faster
than "$o += 1", but at nearly 3 million executions per second, even the
slowest of these will have zero impact on any real program. Ergo, use
whichever style one feels the mosy comfortable with, as I advised.

- --
Eric
$_ = reverse sort qw p ekca lre Js reh ts
p, $/.r, map $_.$", qw e p h tona e; print

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>

iQA/AwUBPzAoJmPeouIeTNHoEQK7swCdFI7/JcPBd4FQALijtkaQV0orx5kAoJJq
58XjK+KtUhRmq8Hyz8VL+a5G
=JPjH
-----END PGP SIGNATURE-----
 
R

--Rick

| \"Dandy\" Randy wrote:
| >
| > Needs some help getting a ... well ... pretty basic math script
working but
| > the solution eludes me .... I have a text file called opened.txt
.... it
| > contains the following single line data:
| >
| > 2000|0|0
| >
| > What I am looking to do is when the script is run, I would like
the second
| > value to increase by 1 .... kind of like this:
|
| #!/usr/bin/perl -p
|
| BEGIN { ( $^I, @ARGV ) = ( '', 'opened.txt' ) }
| s/|(\d+)|/|@{[$1+1]}|/
|
| __END__
|

I couldn't figure out how this one was supposed to work, so I tried it
and couldn't really fix it.

This works though...

#!/usr/bin/perl -p

BEGIN { ( $^I, @ARGV ) = ( '.bak', 'opened.txt' ) }
s/\|(\d+)\|/"|" . ($1+1) . "|"/e;

__END__

Can you explain your version to me? It looks like there is a lot
there I could learn.

--Rick
 
R

--Rick

| --Rick wrote:
| >
| > | > | \"Dandy\" Randy wrote:
| > | >
| > | > Needs some help getting a ... well ... pretty basic math
script
| > | > working but the solution eludes me .... I have a text file
called
| > | > opened.txt ... it contains the following single line data:
| > | >
| > | > 2000|0|0
| > | >
| > | > What I am looking to do is when the script is run, I would
like
| > | > the second value to increase by 1 .... kind of like this:
| > |
| > | #!/usr/bin/perl -p
| > |
| > | BEGIN { ( $^I, @ARGV ) = ( '', 'opened.txt' ) }
| > | s/|(\d+)|/|@{[$1+1]}|/
| > |
| > | __END__
| >
| > I couldn't figure out how this one was supposed to work, so I
tried it
| > and couldn't really fix it.
| >
<snip>
|
| Sorry, I forgot to backwack the veritcal bars. :)
|
| #!/usr/bin/perl -p
|
| BEGIN { ( $^I, @ARGV ) = ( '', 'opened.txt' ) }
| s/\|(\d+)\|/|@{[$1+1]}|/
|
| __END__
|

OK, I'm not so sleepy this time.

I did figure out that the pipe characters needed to be escaped. What
I was really meaning to ask (and I asked poorly) was this. I could
not understand the idiom you used to get addition into the replacement
string nor could I make it work (surprise!). What I got instead was a
printed addition problem. Could you explain it or point me to the
right place in the documentation?

Thanks again.

--Rick
 
J

John W. Krahn

--Rick said:
|
| Sorry, I forgot to backwack the veritcal bars. :)
|
| #!/usr/bin/perl -p
|
| BEGIN { ( $^I, @ARGV ) = ( '', 'opened.txt' ) }
| s/\|(\d+)\|/|@{[$1+1]}|/

OK, I'm not so sleepy this time.

I did figure out that the pipe characters needed to be escaped. What
I was really meaning to ask (and I asked poorly) was this. I could
not understand the idiom you used to get addition into the replacement
string nor could I make it work (surprise!). What I got instead was a
printed addition problem. Could you explain it or point me to the
right place in the documentation?

Well, it works fine for me. :)

$ perl -le'
$_ = "1234|12|5678";
print;
s/\|(\d+)\|/|@{[$1+1]}|/;
print;
'
1234|12|5678
1234|13|5678


The "@{[ ]}" idiom is described in the FAQ:

perldoc -q "How do I expand function calls in a string"



John
 
R

--Rick

| --Rick wrote:
| >
| > | > |
| > | Sorry, I forgot to backwack the veritcal bars. :)
| > |
| > | #!/usr/bin/perl -p
| > |
| > | BEGIN { ( $^I, @ARGV ) = ( '', 'opened.txt' ) }
| > | s/\|(\d+)\|/|@{[$1+1]}|/
| >
| > OK, I'm not so sleepy this time.
| >
| > I did figure out that the pipe characters needed to be escaped.
What
| > I was really meaning to ask (and I asked poorly) was this. I
could
| > not understand the idiom you used to get addition into the
replacement
| > string nor could I make it work (surprise!). What I got instead
was a
| > printed addition problem. Could you explain it or point me to the
| > right place in the documentation?
|
| Well, it works fine for me. :)
|
| $ perl -le'
| $_ = "1234|12|5678";
| print;
| s/\|(\d+)\|/|@{[$1+1]}|/;
| print;
| '
| 1234|12|5678
| 1234|13|5678
|
|
| The "@{[ ]}" idiom is described in the FAQ:
|
| perldoc -q "How do I expand function calls in a string"
|

Egad! I asked a FAQ! I was blindly looking for expanding functions
in regexen and it didn't occur to me that it was just a string.
Still, I learned something useful. Thanks for pointing me to the
answer.

And, yes, on my second session it did work for me, although I had to
put an extension for in-place edit.

--Rick {apparently an eternal beginner =0)}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top