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

Greetings. I have some code that runs beautifully under Perl 5.004_04 on Solaris 6. We are in the process of upgrading our server to Solaris 9 and in the process, upgrading Perl to 5.8.0. I have been testing the scripts that we currently have in production on the on Solaris 6 with the new OS and Perl. Everything this seems to work fairly well, however, I have noticed one problem. I am dup'ing STDOUT and STDERR to a log file so that if there is output from some of the external programs we run, we can capture it. This runs perfectly under the older version of Perl. However, the same code does not behave quite the same under Perl 5.8.0.

Example of code in question:

open (STDOUT, ">$log_dir/$process.log") or exit 1; open (STDERR, ">&STDOUT") or exit 2; flock(STDOUT, LOCK_EX | LOCK_NB) or exit 3; truncate STDOUT, 0; #clear out STDOUT to start with a fresh log file. print "This is my log file.\n"; qx!someprogramtorun!; (do some more stuff) __DATA__ (what I see in the log file) This is my log file.

With the older version, I would also have captured the output from qx!someprogramtorun!. However, that is not being captured when run under Perl 5.8.0. Now, this is not a big problem for most external programs we use, but it causes one that we run to error out for some inexplicable reason. If I capture STDOUT and STDERR to a log file from the commandline with something like: my_program.pl >log.t 2>&1, everything runs perfectly. I capture both those lines that I want printed and anything incidental that the external programs throw out. I'm sure that what I am doing is not ideal, but it was working. I'd prefer not to have to do all the commandline redirections if it can be avoided. What am I missing? As far as I can determine, the output from qx!! is the only thing effected. I can't determine if the problem is with how I'm redirecting STDOUT and STDERR with open() or what.

Thanks in advance.

update: added line into code example to indicate that I need to retain control of the program after the qx!!.


"Ex libris un peut de tout"

Replies are listed 'Best First'.
Re: Problem dup'ing STDOUT
by Thelonius (Priest) on Nov 26, 2003 at 18:40 UTC
    As Joost points out, system is the correct way to do this, but there is one caveat. Apparently--see 271092--it's not guaranteed that STDOUT is reopened on file descriptor 1 and STDERR on file descriptor 2. Thus it would be safer to code this way:
    open (STDOUT, ">$log_dir/$process.log") or die "cannot open log: $!\n" +; if (fileno(STDOUT) != 1) { use POSIX; POSIX::dup2(fileno(STDOUT), 1) or die "dup2: $!\n"; } open (STDERR, ">&STDOUT") or exit 2; flock(STDOUT, LOCK_EX | LOCK_NB) or exit 3;
Re: Problem dup'ing STDOUT
by holo (Monk) on Nov 26, 2003 at 16:41 UTC

    You should be using exec instead of qx//

      Perhaps, but when I read in the Camel Book about exec, it indicates that "The exec function terminates teh current program and executes an external command and never returns!!! Use system instead of exec." I do not want the program to terminate, I need to retain control to do other things. Perhaps my example wasn't as explicit as it should have been.


      "Ex libris un peut de tout"
        Does exactly the same thing as "exec LIST", except that a fork is done first

        From system documentation. It is equivalent to a fork/exec, just more efficient.

        The point is that qx// returns the output as a scalar or array but does not explictly print anything to STDOUT (as it used to be in the old days in null context apparently).

        Use system instead of exec.
        Like it says; just use system instead of exec (or qr//) and you'll be allright.

        Joost.

        -- #!/usr/bin/perl -w use strict;$;= ";Jtunsitr pa;ngo;t1h\$e;r. )p.e(r;ls ;h;a;c.k^e;rs ";$_=$;;do{$..=chop}while(chop);$_=$;;eval$.;