2

i find this in one sample script, then i search from google and found the following words,

Note that you cannot simply open STDERR to be a dup of STDOUT in your Perl program and avoid calling the shell to do the redirection. This doesn't work:

open(STDERR, ">&STDOUT");

This fails because the open() makes STDERR go to where STDOUT was going at the time of the open(). The backticks then make STDOUT go to a string, but don't change STDERR (which still goes to the old STDOUT).

Now I am confused. What exactly is the meaning of open(STDERR, ">&STDOUT"); ?

zdim
  • 64,580
  • 5
  • 52
  • 81
tonyibm
  • 581
  • 2
  • 8
  • 24
  • https://perldoc.pl/perlfunc#open-FILEHANDLE%2CEXPR – Shawn Jul 07 '19 at 03:16
  • 1
    The stuff you quote "from google" mentions backticks, but you don't show that part of what it was talking about; I suspect that will help it make more sense – ysth Jul 07 '19 at 06:53

2 Answers2

6

With the & in the mode >& in the call

open STDERR, ">&STDOUT";  # or: open STDERR, ">&", \*STDOUT

the first given filehandle is made a copy of the second one. See open, and see man 2 dup2 since this goes via dup2 syscall. The notation follows the shell's I/O redirection. Since here the first filehandle exists (STDERR) it is first closed.

The effect is that prints to STDERR will go to where STDOUT was going before this was done, with the side effect of the original STDERR being closed.

This is legit and does not result in errors but is not a good way to redirect STDERR in general -- after that we cannot restore STDERR any more. See open for how to redirect STDERR.

The rest of the comment clearly refers to a situation where backticks (see qx), which redirect STDOUT of the executed command(s) to the program, are used after that open call. All this seems to refer to an idea of redirecting STDERR to STDOUT in this way.

Alas, the STDERR, made by that open call to go where STDOUT was going, doesn't get redirected by the backticks and thus still goes "there." In my case prints to STDERR wind up on the terminal as I see the warning (ls: cannot access...) with

perl -we'open STDERR, ">&STDOUT"; $out = qx(ls no_such)'

(unlike with perl -we'$out = qx(ls no_such 2>&1)'). Explicit prints to STDERR also go to the terminal as STDOUT (add such prints and redirect output to a file to see).

This may be expected since & made a copy of the filehandle, so the "new" one (the former STDERR) still goes where STDOUT was going, that is to the terminal. What is of course unintended in this case and thus an error.


 Every program in UNIX gets connected to standard streams stdin, stdout, and stderr, with file descriptors 0, 1, and 2 respectively. In a Perl program we then get ready filehandles for these, like the STDERR (for fd 2).

Some generally useful posts on manipulations of file descriptors in the shell:

zdim
  • 64,580
  • 5
  • 52
  • 81
2

It's basically dup2(fileno(STDOUT), fileno(STDERR)). See your system's dup2 man page.

In short, it associates STDERR with the same stream as STDOUT at the system level. After the command is performed writing to either will be the same as writing to STDOUT before the change.

Unless someone's messed with STDOUT or STDERR, it's equivalent to the shell command

exec 2>&1
ikegami
  • 367,544
  • 15
  • 269
  • 518