tags:

views:

233

answers:

6
perl -e 'system ("crontab1 -l");print $?'

returns -1 as expected (program crontab1 doesn't exist)

perl -e 'system ("crontab1 -l|grep blah");print $?'

returns 256.

What is the way to check the status of the first (or both) programs?

+2  A: 

You are getting the exit status of the entire command, just as you should. If you want the exit status separately, you're going to have to run the commands separately.

#!/usr/bin/perl -e
system("crontab1 -l > /tmp/junk.txt"); print $?;
system("grep blah /tmp/junk.txt"); print $?;

as an example.

Michael Kohne
@Michael Kohne, by "output" do you mean "termination status"? The OP doesn't want to differentiate his subprocesses' *output*, but their exit statuses.
pilcrow
@pilcrow: thanks. Edited to fix.
Michael Kohne
This is helpful, but now I would need an error handling for a file access.For example this: perl -e 'system("crontab1 -l > /blah"); print $?;' still gives me 256. I guess I would need to split it further :)
vt
No need for a temp file. JB has a better answer below.
runrig
+1  A: 

If you want to check the status, don't put them all in the same system. Open a reading pipe to the first program to get its output then open another pipe to the other program.

brian d foy
A: 

The operating system returns an exit status only for the last program executed and if the OS doesn't return it, perl can't report it.

I don't know of any way to get at the exit code returned by earlier programs in a pipeline other than by running each individually and using temporary files instead of pipes.

Dave Sherohman
+2  A: 

Remember, you're supposed to use $?>>8 to get the exit code, not $?

perl -e 'system("set -o pipefail;false | true");print $?>>8,"\n"'

1

This ("pipefail") only works if your shell is bash 3. Cygwin and linux ship with it; not sure about mac.

You should be aware that 256 is an error return. 0 is what you'd get on success:

perl -e 'system("true");print $?>>8,"\n"'

0

I didn't know system returned -1 for a single command that isn't found, but $?>>8 should still be non-zero in that case.

wrang-wrang
You should really be using POSIX::WEXITSTATUS instead of right shifting
Hasturkun
Even with the right shifting it's still not a -1 I was looking for.
vt
Hasturkun
+4  A: 

If you tolerate using something other than system, there are easier solutions. For example, the results method in IPC::Run returns all exit codes of the chain.

JB
I'm sure IPC::Run is great, but back when I was looking for something similar I found Proc::SafeExec first. It worked great, though seems a little more verbose then IPC::Run. It's nice to have options :-)
runrig
Good info, thanks, but IPC is currently not a part of the project, prefer not to introduce new dependency at this time.
vt
@vt: you can accomplish something similar with open(..., "-|", ...) or open(..., "|-", ...) (fork with STDIN/STDOUT attached between child processes), and exec(...), but IPC::Run or Proc::SafeExec is so much easier to use. I'd get over your preference if I were you, rather than using a temp file (which is another type of dependency). I have some code here: perlmonks.org/?node_id=246397
runrig
A: 

What is the way to check the status of the first (or both) programs?

There is no such way, at least, not as you have constructed things. You may have to manage sub-processes yourself via fork(), exec() and waitpid() if you must know these things.

Here is roughly what is happening in your code fragment.

  1. perl's system() spawns a shell, and perl wait()s for that subprocess to terminate.

  2. The shell sets up a pipeline:

    1. a subshell exec()s grep on the read-end of the pipe
    2. a subshell fails to locate crontab1 anywhere in $PATH, and exit()s 127 (on my system, that is, where 127 is the shell indicating failure to find a program to run).
  3. grep detects end-of-file on its input and, having matched nothing, exit()s 1.

  4. The shell exit()s with the exit code of the last process in the pipeline, which, again, is 1.

  5. perl detects the shell's exit code of 1, which is encoded in $? as 256.
    (256 >> 8 == 1)

pilcrow
This is helpful - thank you
vt