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

Why is the exit code -1 in the first one-liner? I would have expected it to be the same as the second one-liner.
>perl -e '$code=system("exit 3"); print("Finished with $? (or ",$?>>8, +") $code (or ",$code>>8,")\n");' Finished with -1 (or 72057594037927935) -1 (or 72057594037927935) >perl -e '$code=system("ps > /dev/null;exit 3"); print("Finished with +$? (or ",$?>>8,") $code (or ",$code>>8,")\n");' Finished with 768 (or 3) 768 (or 3)
Background: I have a script that does a fork and a system call (followed by an exit with the system's return code) in the child and the parent eventually (after some other stuff) calls waitpid($pid,0) (possibly after the child has exited). I didn't know why I was getting -1, thus the sanity check above. It may not be an apples to apples comparison, but in either case, I don't undersstand what is going on.

Replies are listed 'Best First'.
Re: Why is this exit code -1?
by haukex (Archbishop) on Nov 07, 2018 at 17:29 UTC

    Have a look at the documentation (Update: you'll also find some example code there how to inspect system for errors):

    Return value of -1 indicates a failure to start the program or an error of the wait(2) system call (inspect $! for the reason).

    And turn on warnings:

    $ perl -wMstrict -le 'print system("exit 3");print "<$!>"' Can't exec "exit": No such file or directory at -e line 1. -1 <No such file or directory>

    exit is a shell builtin, not an actual system command.

    $ which exit $ perl -wMstrict -le 'print system(q{/bin/bash -c "exit 3"}); print "<$!>\n",$?>>8' 768 <> 3

    And the AM post explains why the shell doesn't get called in my first example above:

    $ perl -wMstrict -le 'system("pstree -A $$ ")==0 or die;' perl---pstree $ perl -wMstrict -le 'system("pstree -A $$;")==0 or die;' perl---sh---pstree

    By the way, I can recommend IPC::System::Simple because of its better error handling, and I would also recommend avoiding the shell, if possible - I wrote about the issues with it here, and fellow monk afoken wrote about The problem of "the" default shell.

Re: Why is this exit code -1?
by ikegami (Patriarch) on Nov 07, 2018 at 17:18 UTC

    Note: system sets and returns $?, so $code and $? will always have the same value.

    Note: When $? is -1, the program couldn't be executed, and the reason is found in $!.

Re: Why is this exit code -1?
by Anonymous Monk on Nov 07, 2018 at 17:13 UTC
    Sometimes Perl tries to be smart and avoid launching the shell (notice no /bin/sh being executed):
    $ strace -fe execve perl -e '$code=system("exit 3"); print("Finished w +ith $? (or ",$?>>8,") $code (or ",$code>>8,")\n");' execve("/usr/bin/perl", ["perl", "-e", "$code=system(\"exit 3\"); prin +t(\"F"...], [/* 51 vars */]) = 0 strace: Process 24553 attached [pid 24553] execve("/home/username/perl5/bin/exit", ["exit", "3"], [/* + 51 vars */]) = -1 ENOENT (No such file or directory) [pid 24553] execve("/usr/local/bin/exit", ["exit", "3"], [/* 51 vars * +/]) = -1 ENOENT (No such file or directory) [pid 24553] execve("/usr/bin/exit", ["exit", "3"], [/* 51 vars */]) = +-1 ENOENT (No such file or directory) [pid 24553] execve("/bin/exit", ["exit", "3"], [/* 51 vars */]) = -1 E +NOENT (No such file or directory) [pid 24553] execve("/usr/local/games/exit", ["exit", "3"], [/* 51 vars + */]) = -1 ENOENT (No such file or directory) [pid 24553] execve("/usr/games/exit", ["exit", "3"], [/* 51 vars */]) += -1 ENOENT (No such file or directory) [pid 24553] execve("/home/username/.local/bin/exit", ["exit", "3"], [/ +* 51 vars */]) = -1 ENOENT (No such file or directory) [pid 24553] +++ exited with 255 +++ --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=24553, si_ui +d=1000, si_status=255, si_utime=0, si_stime=0} --- Finished with -1 (or 72057594037927935) -1 (or 72057594037927935) +++ exited with 0 +++
    But when it notices enough special characters in the command line, a real shell is launched:
    $ strace -fe execve perl -e '$code=system("ps > /dev/null;exit 3"); pr +int("Finished with $? (or ",$?>>8,") $code (or ",$code>>8,")\n");' execve("/usr/bin/perl", ["perl", "-e", "$code=system(\"ps > /dev/null; +exi"...], [/* 51 vars */]) = 0 strace: Process 24618 attached [pid 24618] execve("/bin/sh", ["sh", "-c", "ps > /dev/null;exit 3"], [ +/* 51 vars */]) = 0 strace: Process 24619 attached [pid 24619] execve("/bin/ps", ["ps"], [/* 51 vars */]) = 0 [pid 24619] +++ exited with 0 +++ [pid 24618] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid= +24619, si_uid=1000, si_status=0, si_utime=0, si_stime=1} --- [pid 24618] +++ exited with 3 +++ --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=24618, si_ui +d=1000, si_status=3, si_utime=0, si_stime=0} --- Finished with 768 (or 3) 768 (or 3) +++ exited with 0 +++
    This is described in the first paragraph of perldoc -f system:
    If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is /bin/sh -c on Unix platforms, but varies on other platforms). If there are no shell metacharacters in the argument, it is split into words and passed directly to execvp, which is more efficient.