in reply to Re: redirect output from a command to another command
in thread redirect output from a command to another command

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.

Replies are listed 'Best First'.
Re^3: redirect output from a command to another command
by ikegami (Patriarch) on Mar 02, 2011 at 02:49 UTC

    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?
        «& ~MASK» turns off bits MASK, and this was the intent.

      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

        Source of what?

        bash

        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?

        File descriptors are per process. You only have to make sure it's not used by the current process.

        I also don't understand the close on exec thing.

        Running a command in unix requires duplicating the current process using fork then calling exec to replace the program being run in the process. system is a wrapper around these.

        The close-on-exec flag determines whether the file handle will available after the exec or not. In a sense, whether the handle is inherited by the child process or not. fd 0, 1 and 2 must not be close-on-exec (or else the command won't have an open stdin, stdout and stderr) and the handle for <() must not be either.

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

        Correcting myself, I think it's more that the user might later want to use fd 3. For example,

        command <( command ) >&3