YuckFoo has asked for the wisdom of the Perl Monks concerning the following question:

Does anyone know why an open command with a pipe and quotes doesn't die, but with the same command without the quotes dies. Like this:

OpenFoo

This is perl, v5.6.0 built for i386-linux

#!/usr/bin/perl open (CMD, '-|', "boguscommand 'filename'") or die "Uh-oh $!"; print "Oops, I didn't die\n"; open (CMD, '-|', "boguscommand filename") or die "Uh-oh $!"; print "But I did\n";
Update: Thanks guys, I didn't think that quote (') was a shell metacharacter and it's not listed in the bash manpage as one.

Replies are listed 'Best First'.
Re: open won't die
by Abigail-II (Bishop) on Oct 28, 2003 at 22:17 UTC
    It's documented in perldoc -f system.

    The first command contains characters special to the shell, so the entire thing (boguscommand 'filename') is handed to the shell. The second doesn't contain special characters, so Perl splits the string on whitespace and calls execvp directly - which will return an error if the command can't be found.

    Abigail

Re: open won't die
by sauoq (Abbot) on Oct 28, 2003 at 22:19 UTC

    Because perl is successfully starting a process: the shell. It needs to start the shell to deal with the shell metacharacters, the quotes. Here's the explanation from perldoc perlopentut:

    What happens if you try to open a pipe to or from a non-existen +t com- mand? If possible, Perl will detect the failure and set $! as +usual. But if the command contains special shell characters, such as " +>" or "*", called 'metacharacters', Perl does not execute the command directly. Instead, Perl runs the shell, which then tries to ru +n the command. This means that it's the shell that gets the error in +dica- tion. In such a case, the "open" call will only indicate failu +re if Perl can't even run the shell. See "How can I capture STDERR f +rom an external command?" in perlfaq8 to see how to cope with this. T +here's also an explanation in perlipc.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: open won't die
by graff (Chancellor) on Oct 28, 2003 at 23:32 UTC
    ... I didn't think that quote (') was a shell metacharacter and it's not listed in the bash manpage as one.

    Okay, technically, quotation marks are not called "metacharacters" in the bash man page -- the first thing you find is this:

    DEFINITIONS
     ...
     metacharacter
          A  character  that, when unquoted, separates words.
          One of the following:
          |  & ; ( ) < > space tab
    
    But then farther down (way farther -- bash has a big man page), there's a whole "chapter" called QUOTING, which makes it clear that single and double quotes have special (distinct) meanings in shell commands. It's this notion of "having special meaning to the shell" that defines the set of things counted as "metacharacters" in a pipeline command string that you pass the perl's open() call. Granted, the terminology is a little slippery here.
      Thanks graff,

      With some thought I realized it doesn't matter what the sh or bash consider metacharacters, its what Perl considers metacharacters that counts.

      From perldoc -f quotemeta, its: "all char­acters not matching '/A-Za-z_0-9/' "

      YuckFoo

        What's considered a character special to the shell is *not* the same as all characters not matching /[A-Za-z_0-9]/. This is immediately obvious from the example of the OP. Both examples contain a space, a space is not matched by /[A-Za-z_0-9]/, yet in one case the shell is called, in another it isn't.

        Here's another example:

        $ perl -wle 'exec ", foo" or die' Can't exec ",": No such file or directory at -e line 1. Died at -e line 1.
        No shell called, even with a comma present.

        Abigail

Re: open won't die
by YuckFoo (Abbot) on Oct 29, 2003 at 19:13 UTC
    Here is a pointer to the best example I could find that throughly checks the success of the open(), close(), and the 'piped' program. It's a bit cumbersome. To my surprise it was documented on the close page. I haven't been there for a while.

    YuckFoo

    open(OUTPUT, '|sort >foo') # pipe to sort or die "Can't start sort: $!"; #... close OUTPUT # wait for sort to finish or warn $! ? "Error closing sort pipe: $!" : "Exit status $? from sort";