Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.85k stars 527 forks source link

`perl -e FILE.pl` and `perl -E FILE.pl` both "fail" silently, exit status `$?` is `0` #22107

Closed oodler577 closed 1 month ago

oodler577 commented 1 month ago

Description

It was discovered while going through Effective Perl Programming book (page 13), the following examples fail (or succeeds?) silently and with an exit status ($?) of 0 (success):

  perl -e FILE.pl

and

  perl -E FILE.pl

This only happens if there is no file path separator.

Steps to Reproduce

  1. cd to a directory with any Perl script (e.g., foo.pl)
  2. run either: perl -e foo.pl perl -E foo.pl
  3. observe after, $? is set to 0: echo $?

Expected behavior

We found this during a group Perl study session. We all expected that there to be an error, warning, or $? set as non-0 since this was an existing file.

Perl configuration

% perl -v

This is perl 5, version 38, subversion 2 (v5.38.2) built for darwin-thread-multi-2level

Copyright 1987-2023, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at https://www.perl.org/, the Perl Home Pag

Note, this might be a very old bug. It is even present in the Effective Perl Programming book, 2nd Edition (page 13):

image

CC'ing some present if they wish to correct or amend the report: @Util, @haxmeister

oodler577 commented 1 month ago

@briandfoy might also have more insight. ty!

Grinnz commented 1 month ago

Why would you expect an error? The -e and -E options take code, not a filename, and 'foo.pl' is a valid Perl script with no strict or warnings enabled. (It creates two strings and concatenates them)

Grinnz commented 1 month ago

See https://perldoc.perl.org/perlrun#-e-commandline

If -e is given, Perl will not look for a filename in the argument list.

oodler577 commented 1 month ago

Well, it seems it allowed for a false positive code test to slip through in the aforementioned book; I am assuming they tested to code in the book. Maybe it should be an error. It was surprising.

Grinnz commented 1 month ago

While the first edition of that book is as old as the oldest version of that documentation I can find (linked below), there is no reasonable way to make that an error because most valid perl code can be a file path and most filepaths will be valid perl code. I can only assume it is an error in the book.

https://perldoc.perl.org/5.005/perlrun#-e-commandline

oodler577 commented 1 month ago

It is an error in that book. If they tested the code, there was no way to detect that was an error - even now. That's the problem. If there is a way to differentiate that from code, then it should throw an error. That's purpose of this issue. Is it a bug with -e or -E, or is it just a potential edge case that should be detected? Can it even be detected?

oodler577 commented 1 month ago

Note,

shell# echo > bin/foo.pl
shell# perl -e bin/foo.pl
Illegal division by zero at -e line 1.
shell# echo $?
255
shell# cd bin
shell# perl -e ./foo.pl
syntax error at -e line 1, near "."
Search pattern not terminated at -e line 1.
shell# echo $?
255
shell# perl -E ./foo.pl
syntax error at -e line 1, near "."
Search pattern not terminated at -e line 1.
shell# echo $?
255
shell# perl -e foo.pl
shell# echo $?
0
shell# perl -E foo.pl
shell# echo $?
0

I understand the error state is due to it being taken as literal Perl code; at least it fails if there is a forward slash (albeit it in at least 2 ways). With no file path separator, it doesn't even fail. False positive and I suspect the root cause of the "bug" in the book's code. Maybe if the code looks like a file path (even with out a leading ./) there should be a check to see if the file exists, if not fall back to the existing syntax error.

It'll fail if there is a leading . - again, not for the right reason, but at least it fails.

shell# mv foo.pl .foo.pl
shell# perl -E .foo.pl
syntax error at -e line 1, near "."
Execution of -e aborted due to compilation errors.
shell# echo $?
255

Maybe provide a warning?

mauke commented 1 month ago

Maybe if the code looks like a file path

All code looks like a file path. use strict; use warnings; print "Hello, world!\n" is a valid filename on Linux.

Can you explain what exactly you want perl to do to detect this case? Because I don't see a way to change anything without breaking the existing documented behavior of perl in other cases.

Maybe provide a warning?

You explicitly did not enable warnings. If you had:

$ perl -we file.pl
Unquoted string "file" may clash with future reserved word at -e line 1.
Unquoted string "pl" may clash with future reserved word at -e line 1.
Useless use of a constant ("filepl") in void context at -e line 1.
Util commented 1 month ago

I see now. When running perl -e FILE.pl, we observed that the instructions in the program FILE.pl did not execute, and assumed that program contained in the file FILE.pl was being read and somehow run incorrectly due to -e.

The -w option clued me in, and allowed me to read everyone's reply to this issue differently than I had been reading them. The -e option (just as documented) does stop Perl from looking for a file-full-of-code, and looks for code to execute from the rest of the command-line. Without -w, Perl is in "poetry mode", and happily processes what we think of as a filename, as if it were code.

In this light, I see that perl -e FILE.pl should produce the same result as: $ cat > realfile.pl FILE.pl ^D $ perl realfile.pl and it does exactly that. Both produce exactly the same nothing. No warnings are appropriate because we did not say -we or -wE as we should have.

I still think the lines from the book are misleading to the point of being erroneous, but this -e behavior is not the bug in Perl that we thought it was.

oodler577 commented 1 month ago

I am just reporting it. Seems like a rather special case to consider, especially since it's forever preserved in the 2nd edition of Effective Perl Programming, page 13. And someone typing it is is left perplexed about why it did nothing visible, yet returned $? of 0 - but was expecting the file to be run. That's all I got.

oodler577 commented 1 month ago

I still think the lines from the book are misleading to the point of being erroneous, but this -e behavior is not the bug in Perl that we thought it was.

I am saying this is an undetectable error in the book's code, that clearly the authors would have fixed had it thrown a warning or $? other than 0. It is a false positive, impossible to detect in this specific case.

mauke commented 1 month ago

It's easy to create "undetectable" errors if you don't enable strict (without strict, perl basically runs in perl 4 compatibility mode) or warnings/-w (which is for compatibility with perl 1.0!). For example, this program that tries to count lines with "word" in them:

$ printf 'a\nword\nb\nword\n' | perl -nle 'BEGIN { $count = 0; } $conut++ if /word/; END { print "$count occurrences found" if $count; }'
$

No output; exit status is 0.

oodler577 commented 1 month ago

I still think the lines from the book are misleading to the point of being erroneous, but this -e behavior is not the bug in Perl that we thought it was.

Yeah not a bug, seems to be like a special edge case that a normal person might make and be mystified about. Doesn't Perl have "looks like you meant to, blah blah blah" errors in other places? That's what I am thinking would be a good warning.

It's easy to create "undetectable" errors.

Yeah but your example is a mess that nobody would mistake for a file name. The one here looks like a file name and has been reproduced in print, probably thousands of times. If those authors can make that mistake and also not be able to detect it, then maybe it's more commonly made than you think. I bet thousands of genius Perl programmers and n00bies a like, have looked at that and though it was just running a file. Anyway. Good night.

Grinnz commented 1 month ago

It is unfortunate, but the documentation is very clear.

iabyn commented 1 month ago

On Wed, Mar 27, 2024 at 11:21:54PM -0700, OODLER wrote:

Doesn't Perl have "looks like you blah blah blah" errors in other places? That's what I am thinking would be a good warning.

Yes, perl does. And if you enable warnings and strict, it will will display those warnings or errors. In this particular case, what you seem to be asking for is:

I really can't see how you could avoid false positives. Is 'foo' possibly a filename? Looks like one to me. So should this be an error? perl -MFoo -e foo

Or maybe you want something narrow, like /^\w+.pl$/i ?

-- Dave's first rule of Opera: If something needs saying, say it: don't warble it.

Leont commented 1 month ago

An unfortunate misprint in that book, that's their problem to errata not ours.

briandfoy commented 1 month ago

This is just an error in the book. If you turn on warnings you get the hint:

$ perl -we FILE.pl
Unquoted string "pl" may clash with future reserved word at -e line 1.
Useless use of a constant ("FILEpl") in void context at -e line 1.
$ echo $?
0

Perl will treat bare words that don't have a definition as a string. It then concatenates those strings and warns about the void context.

Add strict and you get your error:

$ perl -Mstrict -we FILE.pl
Bareword "FILE" not allowed while "strict subs" in use at -e line 1.
Bareword "pl" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
$ echo $?
255

Our mistake is not so much about this being a weird situation, but simply managing to intersperse code with text. As you are writing you have a bag of ideas and you move things around. Sometimes the code in the text is changed but not reverified. I don't know how this particular error got in there. We had a Google sheet that had a list of all the reported errata, but that has disappeared.

haxmeister commented 1 month ago

I know where some confusion may be.

Please not that in the current perldocs we see the e|E option defined like this:

[ [-e|-E] 'command' ] [ -- ] [ programfile ] [ argument ]...

The "--" is of course the differentiating factor. However, by the documents themselves this is a valid ending to any switch, not just -e. I think a modification of that line in perldoc would remove confusion, and yes the book is in error.

oodler577 commented 1 month ago

Thank you @briandfoy and everyone. I get -e and -E is maximally permissive, I've made a note in my book that this was a small error in regard to what those flags accept (and why it works without -w).

@haxmeister - that is confusing, but not the original part of my consideration here. Had I read that I'd been even more confused! 😄