failing to apply eval to a string

A

Avner

I want to create a parametrized check of the file type. Something like:
return unless -f $_
where the -f may be changed to -d in a different scenario. So I create
a variabled string and apply eval to the string:

e.g.
$fileType = "-f";
$cmdLine = "return unless $fileType $_";
print "cmdLine: $cmdLine\n";
eval $cmdLine;

If I type the "return unless -f $_" the perl code acts correctly but if
creating a variabled string and appling eval to it the code fails.
Printing the cmdLine looks ok (it prints to the screen "cmdLine: return
unless -f ." where . is the checked file
but then I get the following error from the eval line
Warning: Use of "-f" without parens is ambiguous at (eval 1) line 1.
Error code: syntax error at (eval 1) line 2, at EOF

What's wrong?

Thanks,
Avner
 
U

usenet

Avner said:
but then I get the following error from the eval line
Warning: Use of "-f" without parens is ambiguous at (eval 1) line 1.

Maybe Perl is actually telling you what's wrong - maybe you ought to
use parens (and quote your filename, since you're doing this as a
string eval):

my $cmdLine = "return unless $fileType ('$_')";

FWIW, though, what you posted seems like a bit of a kludge...
 
X

xhoster

Avner said:
I want to create a parametrized check of the file type. Something like:
return unless -f $_
where the -f may be changed to -d in a different scenario. So I create
a variabled string and apply eval to the string:

I wouldn't use eval in this context.

if ($fileType eq "-f) {
return unless -f $_;
} elsif ($fileType eq "-d") {
return unless -d $_;
} else {
die "Unsupported fileType $fileType"
};
e.g.
$fileType = "-f";
$cmdLine = "return unless $fileType $_";
print "cmdLine: $cmdLine\n";
eval $cmdLine;

If I type the "return unless -f $_" the perl code acts correctly but if
creating a variabled string and appling eval to it the code fails.
Printing the cmdLine looks ok (it prints to the screen "cmdLine: return
unless -f ." where . is the checked file

.. should be the quoted filename, or a variable. Not a bareword of the
checked filename, which is what you probably have.

Xho
 
A

Avner

I tried it and it stll doesn't work
Changing to
$cmdLine1 = "return unless $fileType ('$_')";

prints:
cmdLine1: return unless -f ('.')

and does nothing (does not return when checking the current directory
file ".")
 
A

Avner

Thanks Xho for your answer.

I could do the if testing as you suggested but I don't want to limit
the combinations of fileType parameter. I want to leave it open for any
combination without having to update the code each time a new fileType
comes.

Also, next I planned on doing a check on the extention of the file.
Something like

$excludeFileExtFlag = "\.in\|\.h\$\|\.cpp\$\|\.c\$";
return unless ($_ =~/$excludeFileExtFlag/);

There as well I wouldn't want to introduce logic to my code and update
the if block every time a new extention comes around.

Could you explain why eval fails at the first place?
Why won't it simply run the command as is? (the command prints out
exactly as if it was typed into the code)

Thanks,
Avner
 
T

Tad McClellan

Avner said:
I want to create a parametrized check of the file type. Something like:
return unless -f $_
where the -f may be changed to -d in a different scenario. So I create
a variabled string and apply eval to the string:

If I type the "return unless -f $_" the perl code acts correctly but if
creating a variabled string and appling eval to it the code fails.
Printing the cmdLine looks ok (it prints to the screen "cmdLine: return
unless -f ." where . is the checked file


That does NOT look ok to me...

Compare:

return unless -f . # dot is the concatenation operator here

with

return unless -f '.' # dot is a string here

strings need quotes around them.

What's wrong?


You have built the eval string incorrectly.
 
A

Avner

Tad said:
That does NOT look ok to me...

Compare:

return unless -f . # dot is the concatenation operator here

with

return unless -f '.' # dot is a string here

strings need quotes around them.




You have built the eval string incorrectly.
Your argument seems right to me but I don't know how to build the
string correctly.
How should I phrase the command line? I tried changing the fault
command line from
$cmdLine = "return unless $fileType $_";
to (added quotes around $_)
$cmdLine = "return unless $fileType '$_'";
but it didn't help. The printed command is now
return unless -f '.'
and the code still does not catch the dot ('.') file.
Besides, how do I generalize the code to deal with all sorts of file
names?
(the dot file is only one specific file name)

Thanks,
Avner
 
X

xhoster

Avner said:
I tried it and it stll doesn't work
Changing to
$cmdLine1 = "return unless $fileType ('$_')";

prints:
cmdLine1: return unless -f ('.')

and does nothing (does not return when checking the current directory
file ".")

eval statements are "returnable". So the "return" in your string is
returning from the eval to the subrouting, rather than returning from the
subroutine itself. I noticed that the first time, but then forgot to
comment on it. Sorry about that.

So you would want the eval statement to return a logical value, and
have the test and the literal "return" be in the sub itself, not the eval:

$cmdLine1 = "$fileType ('$_')";
return unless eval $cmdLine;

Xho
 
A

Avner

eval statements are "returnable". So the "return" in your string is
returning from the eval to the subrouting, rather than returning from the
subroutine itself. I noticed that the first time, but then forgot to
comment on it. Sorry about that.

So you would want the eval statement to return a logical value, and
have the test and the literal "return" be in the sub itself, not the eval:

$cmdLine1 = "$fileType ('$_')";
return unless eval $cmdLine;

Xho

Xho, that solved the problem and now I know better the nature of the
eval command. You were really helpful. Thanks again.
 
A

Avner

Jim said:
The return will return a value from the eval, not execute a return
statement in the context of the subroutine. However, you can capture
the outcome of the eval in a local variable and use that to test the
outcome of the file test operator:

sub test_file
{
my( $file, $test ) = @_;
my $result;
my $cmd = "\$result = $test '$file'";
eval($cmd);
return unless $result;
...
}

... which may be called as:

test_file('-d',foo);

Thanks for your advise Jim.
 
T

Tad McClellan

Avner said:
Xho, that solved the problem


Unless something "bad" finds its way into $fileType or $_ ...

and now I know better the nature of the
eval command.


If it were my problem to solve, I would use a "dispatch table"
instead, and not have to be worried about the evil string eval.

my %tests = (
f => sub { return -f $_[0] },
d => sub { return -d $_[0] },
);

...

return unless $tests{$fileType}->($_);
 
D

Dave Weaver

Tad McClellan said:
If it were my problem to solve, I would use a "dispatch table"
instead, and not have to be worried about the evil string eval.

my %tests = (
f => sub { return -f $_[0] },
d => sub { return -d $_[0] },
);

I would suggest adding a check along the lines of:

die "test '$fileType' not defined" unless defined $tests{$fileType};
 
A

Anno Siegel

Tad McClellan said:
Avner said:
Xho, that solved the problem


Unless something "bad" finds its way into $fileType or $_ ...

and now I know better the nature of the
eval command.


If it were my problem to solve, I would use a "dispatch table"
instead, and not have to be worried about the evil string eval.

my %tests = (
f => sub { return -f $_[0] },
d => sub { return -d $_[0] },
);

...

return unless $tests{$fileType}->($_);

String eval may still have its place in building the table:

my %tests;
$tests{ $_} = eval "sub { return -$_ shift }" for qw( f d x M);

Now the strings are under program control, there's nothing to be
worried about.

Anno
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top