string substitution problem

D

Dawn Schepleng

Hi :)

I am a novice Perl programmer, and have encountered the following problem.
I can make the following string substitution work:

$high_level_dir = "/ceswbl2/installed/bin"
$low_level_dir = "/ceswbl2/src/sparc/bin";
$line =~ s{$low_level_dir(/\w+)+/(\w+)}{$high_level_dir/$2};

This will correctly take a line like:

/ceswbl2/src/sparc/bin/cec_sim/radar/sps48/cecsimlm

and make substitutions such that $line then equals:

/ceswbl2/installed/bin/cecsimlm.

I'm using \w+ to represent a word with numbers and underscores, and am
using "(", ")", and "/" to be literal, and using the substitution format of
"s{}{}" vice "s///" to be more readable.

However, when I take this working perl substitution and try to invoke it as a
system call like:

system("perl -pi -e 's{$low_level_dir(/\w+)+/(\w+)}{$high_level_dir/$2}'
$real_run_file");

It no longer works. The error occurs in a first-pass parse of the perl script,
and says something line "Unrecognized escape \w passed through
in cepSetGoEnv.pl at line 31".

With the help of a co-worker, we've tried changing "{" "}" to "|" and we've
also tried escaping out the "(" and ")" with no luck.

What is the subtle detail that makes this work in-line, but not when the script
is run w/i the system call?

Any ideas would be appreciated!

Thanks,

Dawn Schepleng
JHU/APL
 
J

Jeff 'japhy' Pinyan

[posted & mailed]

$high_level_dir = "/ceswbl2/installed/bin"

Missing semicolon, by the way.
$low_level_dir = "/ceswbl2/src/sparc/bin";
$line =~ s{$low_level_dir(/\w+)+/(\w+)}{$high_level_dir/$2};

That works as expected, which is good.
system("perl -pi -e 's{$low_level_dir(/\w+)+/(\w+)}{$high_level_dir/$2}'
$real_run_file");

It no longer works. The error occurs in a first-pass parse of the perl
script, and says something line "Unrecognized escape \w passed through in
cepSetGoEnv.pl at line 31".

Right. You've made a double quoted string "perl -pi ..." and it has
backslashed characters in it. In a *regex*, \w means something. In a
double-quoted string, it doesn't. You'll need to DOUBLE the backslash.

print "m/(\\w+)/"; # prints: m/(\w+)/

The other problem you'll encounter is that Perl interpolates $2 when you
make that string you pass to system(). You don't want Perl to do that;
you want Perl to send the literal string '$2' to the system() command so
that when system() runs perl, perl sees $2.

system("perl -pi -e 's{foo(/\\w+)+(/\\w+)}bar\$2}' file");

But here's the nice thing: you don't need to call system() here. The -p
and -i flags just add wrappers around the code you give. If you know what
those wrappers look like, you can write a program that DOES what -pi does.
They're explained in the 'perlrun' manpage:

perldoc perlrun

I'm pretty sure there's an exact example of how to do what -pi does in
your program. Look for the documentation of the -i switch.
 
T

Tassilo v. Parseval

Also sprach Purl Gurl:
Under both perl 5.6 and perl 5.8 this still cops an error message:

"Can't do inplace edit without backup."

Perhaps this is a bug with cygwin / win32 ports?

Partly. It's mainly a limitation of Win32 that doesn't allow altering an
already open file (unless of course you open it solely for changing the
file).

A fix would be to have perl make changes to a temporary copy of the
original file and afterwards do a rename when the -i switch is employed.
So far the user has to do that on his own.

Tassilo
 
B

Big and Blue

Jeff said:
The other problem you'll encounter is that Perl interpolates $2 when you
make that string you pass to system(). You don't want Perl to do that;
you want Perl to send the literal string '$2' to the system() command so
that when system() runs perl, perl sees $2.

system("perl -pi -e 's{foo(/\\w+)+(/\\w+)}bar\$2}' file");

Also, Perl will (or may) pass that through a shell. If you don't
want to deal with ensuring things aren't interpreted by the shell as
well, then pas system a LIST of arguments, rather than a single string.
 
G

Gunnar Hjalmarsson

Tassilo said:
Also sprach Purl Gurl:

Partly. It's mainly a limitation of Win32 that doesn't allow
altering an already open file (unless of course you open it solely
for changing the file).

Does that mean that if a Perl program, that makes use of flock() on
*nix platforms, is run on a Windows platform with flock() disabled,
you still don't need to worry too much about files being corrupted
because of concurrent changes?
 
G

Gunnar Hjalmarsson

Purl said:
No. Concurrent writes under Win32 are a problem which must be
addressed via semaphore locking or one of my locking mechanisms
presented at my website.

Okay, that's what I thought. Suppose my conclusion out from Tassilo's
statement was far too extensive. :)

Btw, flock() works on some Win32 systems. As far as I have understood,
the need for using some other locking method is limited to Windows 95
and 98.

Perl does not honor "permission denied" under Win32. Locking
mechanisms are critical to prevent concurrent writes under Win32
when using Perl.

Thanks for clarifying.
 
J

Jeff 'japhy' Pinyan

system("perl -i.bak -e 's/gurlpurl/purlgurl/e' test.txt") or die "FUBAR $!";

Use of a die causes a script to die at that line but does
not generate any error message.

That's because system() returns false on success, not on failure. You
should either do

system(...) and die "...";

or

system(...) == 0 or die "...";
 
T

Tad McClellan

Jeff 'japhy' Pinyan said:
You
should either do

system(...) and die "...";

or

system(...) == 0 or die "...";


or:

!system(...) or die "...";


Which is what I use, because I'm already used to
writing "somefunc() or die".
 
D

Dave Saville

Mostly true. WinME is also in there. This problem with flock will
appear anytime a "Win32 System" is used. This does not exclude
WinNT5 completely. Possibly OS/2 exhibits this problem, not sure.
Other candidates would be systems using DR-DOS or IBM DOS.

FYI flock() works on OS/2, at least with v5.8.0 - Some time ago I
tested with two scripts as I had the same problem - cgi updating a
common file. One script held an exclusive lock on a file and then
waited on keyboard input - the other tried to get the lock and said
when it did. The latter script just hung until I replied to the first
and it released the lock.

Regards

Dave Saville

NB switch saville for nospam in address
 

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,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top