in reply to redirect output from a command to another command

I don't know the significance of '63', but this is what bash does on my system:
use strict; use warnings; use POSIX qw( dup2 ); open(my $src1_fh, '-|', echo => 'apples') or die("open: $!"); open(my $src2_fh, '-|', echo => 'oranges') or die("open: $!"); dup2(fileno($src1_fh), 63) or die("dup2: $!"); dup2(fileno($src2_fh), 64) or die("dup2: $!"); system(diff => '/dev/fd/63', '/dev/fd/64') >= 0 or die("system: $!"); printf("\$?=%04X\n", $?);
1c1 < apples --- > oranges $?=0100

On systems without /dev/fd, it reportedly uses temporary files.

You could also use named pipes.

Update: What is 64 should be 62.

Replies are listed 'Best First'.
Re^2: redirect output from a command to another command
by Allasso (Monk) on Mar 02, 2011 at 01:39 UTC
    thanks ikegami.

    I am wondering why the file descriptor has to be dup'd to 63 - why you can't just use the file descriptor returned from fileno() directly.

    I can see it doesn't work, but I am wondering why.

      First, it doesn't start at 63 and count up, it starts at 63 and counts down. I should have used 63 and 62, not 63 and 64. The reason given by the source is

      Move FD to a number close to the maximum number of file descriptors allowed in the shell process, to avoid the user stepping on it with redirection and causing us extra work.

      There's no mention of anything being special about fd 63 compared to fd 3 (or whatever) other than the user might be using fd 3 already. Perhaps then it's just the close-on-exec flag that varies.

      use strict; use warnings; use Fcntl qw( F_GETFD F_SETFD FD_CLOEXEC ); use POSIX qw( dup2 ); sub keep_open_on_exec { my ($fh) = @_; my $flags = fcntl($fh, F_GETFD, 0); next if $flags & FD_CLOEXEC == 0; fcntl($fh, F_SETFD, $flags & ~FD_CLOEXEC); } open(my $src1_fh, '-|', echo => 'apples') or die("open: $!"); open(my $src2_fh, '-|', echo => 'oranges') or die("open: $!"); keep_open_on_exec($_) for $src1_fh, $src2_fh; system(diff => '/dev/fd/'.fileno($src1_fh), '/dev/fd/'.fileno($src2_fh +)) >= 0 or die("system: $!"); printf("\$?=%04X\n", $?);

      Bingo!

      1c1 < apples --- > oranges $?=0100

      One other note, apparently some systems use /proc/dev/fd instead of /dev/fd.

        I assume you did not intend to do a bitwise & on line 12?

        A lot of questions here...

        "The reason given by the source is..."

        Source of what?

        It seems to me that picking a (somewhat) arbitrary number to use as a file descriptor, and then dup'ing to that descriptor is a bit risky. How can one be sure that it is not already in use by another process?

        I also don't understand the close on exec thing. We've opened a filehandle which holds the output of the echo command. Do filehandles change descriptor numbers midstream somewhere? If it is closing on exec, does that mean it is closing after the echo command has finished executing? If that were true, then it wouldn't do any good to "keep open" after it has already closed.

        If the user is already using fd3, then why would it get assigned to the echo command output?

        I'm not disputing what you are saying, I just am not understanding why these things are. Your script seems to prove the close on exec thing. I guess one of the things I am wondering is "what exec"?

        thanks, Allasso