FAQ
Perl's open() call allows for one to pass in filehandle names or file
descriptors to cause a dup to happen, with the format being like ">&$fh".
IPC::Open3 allows for the case of filehandle names being used as arguments
to its open3() call, but it does not allow for a numeric descriptor to be
passed, such as ">&3". Specifically, it fails when trying to perform a
fileno() on the fd, while it should just take the value of the handle.

The usefulness of using fd's as arguments can be seen in doing something
like:

my $tty = IO::File->new( '>/dev/tty' ) or die;
my $fileno = $tty->fileno();
open3( '<&STDIN', ">&$fileno", '>&STDERR', 'cat', '/etc/motd' );

...which allows one to cleanly pipe the output of cat to the terminal.

Here is a patch to allow use of ">&$fileno" -style arguments to open3():


*** IPC/Open3.pm.orig Sun Jun 25 05:27:29 2000
--- IPC/Open3.pm Sun Jun 25 16:09:56 2000
***************
*** 84,89 ****
--- 84,90 ----
# fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
# ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
# fixed for autovivving FHs, tchrist again
+ # allow fd numbers to be used, by Frank Tobin
#
# $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
#
***************
*** 136,141 ****
--- 137,148 ----
close $_[0] or croak "$Me: close($_[0]) failed: $!";
}

+ sub xfileno {
+ my ($fh) = @_;
+ return $fh if $fh =~ /^\d+$/; # deal with $fh just being an fd
+ return fileno $fh;
+ }
+
my $do_spawn = $^O eq 'os2' || $^O eq 'MSWin32';

sub _open3 {
***************
*** 164,172 ****
$dup_err = ($dad_err =~ s/^[<>]&//);

# force unqualified filehandles into caller's package
! $dad_wtr = qualify $dad_wtr, $package;
! $dad_rdr = qualify $dad_rdr, $package;
! $dad_err = qualify $dad_err, $package;

my $kid_rdr = gensym;
my $kid_wtr = gensym;
--- 171,179 ----
$dup_err = ($dad_err =~ s/^[<>]&//);

# force unqualified filehandles into caller's package
! $dad_wtr = qualify $dad_wtr, $package unless $dad_wtr =~ /^\d+$/;
! $dad_rdr = qualify $dad_rdr, $package unless $dad_rdr =~ /^\d+$/;
! $dad_err = qualify $dad_err, $package unless $dad_err =~ /^\d+$/;

my $kid_rdr = gensym;
my $kid_wtr = gensym;
***************
*** 181,200 ****
# If she wants to dup the kid's stderr onto her stdout I need to
# save a copy of her stdout before I put something else there.
if ($dad_rdr ne $dad_err && $dup_err
! && fileno($dad_err) == fileno(STDOUT)) {
my $tmp = gensym;
xopen($tmp, ">&$dad_err");
$dad_err = $tmp;
}

if ($dup_wtr) {
! xopen \*STDIN, "<&$dad_wtr" if fileno(STDIN) != fileno($dad_wtr);
} else {
xclose $dad_wtr;
xopen \*STDIN, "<&=" . fileno $kid_rdr;
}
if ($dup_rdr) {
! xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != fileno($dad_rdr);
} else {
xclose $dad_rdr;
xopen \*STDOUT, ">&=" . fileno $kid_wtr;
--- 188,207 ----
# If she wants to dup the kid's stderr onto her stdout I need to
# save a copy of her stdout before I put something else there.
if ($dad_rdr ne $dad_err && $dup_err
! && xfileno($dad_err) == fileno(STDOUT)) {
my $tmp = gensym;
xopen($tmp, ">&$dad_err");
$dad_err = $tmp;
}

if ($dup_wtr) {
! xopen \*STDIN, "<&$dad_wtr" if fileno(STDIN) != xfileno($dad_wtr);
} else {
xclose $dad_wtr;
xopen \*STDIN, "<&=" . fileno $kid_rdr;
}
if ($dup_rdr) {
! xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != xfileno($dad_rdr);
} else {
xclose $dad_rdr;
xopen \*STDOUT, ">&=" . fileno $kid_wtr;
***************
*** 204,211 ****
# I have to use a fileno here because in this one case
# I'm doing a dup but the filehandle might be a reference
# (from the special case above).
! xopen \*STDERR, ">&" . fileno $dad_err
! if fileno(STDERR) != fileno($dad_err);
} else {
xclose $dad_err;
xopen \*STDERR, ">&=" . fileno $kid_err;
--- 211,218 ----
# I have to use a fileno here because in this one case
# I'm doing a dup but the filehandle might be a reference
# (from the special case above).
! xopen \*STDERR, ">&" . xfileno($dad_err)
! if fileno(STDERR) != xfileno($dad_err);
} else {
xclose $dad_err;
xopen \*STDERR, ">&=" . fileno $kid_err;

Search Discussions

  • Mark-Jason Dominus at Jun 25, 2000 at 10:16 pm

    + sub xfileno {
    + my ($fh) = @_;
    + return $fh if $fh =~ /^\d+$/; # deal with $fh just being an fd
    + return fileno $fh;
    + }
    It seems to me that it should take >&=3 as a request to open file
    descriptor 3, the same way that Perl's built-in open does.
  • Frank Tobin at Jun 26, 2000 at 12:01 am

    Mark-Jason Dominus, at 18:21 -0400 on Sun, 25 Jun 2000, wrote:

    It seems to me that it should take >&=3 as a request to open file
    descriptor 3, the same way that Perl's built-in open does.
    Sure, we can do that too. Here's a patch allowing for that also (with a
    bit of factorization upon the previous patch, too, too):

    *** IPC/Open3.pm.orig Sun Jun 25 05:27:29 2000
    --- IPC/Open3.pm Sun Jun 25 18:49:04 2000
    ***************
    *** 84,89 ****
    --- 84,90 ----
    # fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
    # ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
    # fixed for autovivving FHs, tchrist again
    + # allow fd numbers to be used, by Frank Tobin
    #
    # $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
    #
    ***************
    *** 136,141 ****
    --- 137,152 ----
    close $_[0] or croak "$Me: close($_[0]) failed: $!";
    }

    + sub xfileno {
    + my ($fh) = @_;
    + return $1 if $fh =~ /^=?(\d+)$/; # deal with $fh just being an fd
    + return fileno $fh;
    + }
    +
    + sub fh_is_fd {
    + return $_[0] =~ /^=?\d+$/;
    + }
    +
    my $do_spawn = $^O eq 'os2' || $^O eq 'MSWin32';

    sub _open3 {
    ***************
    *** 164,172 ****
    $dup_err = ($dad_err =~ s/^[<>]&//);

    # force unqualified filehandles into caller's package
    ! $dad_wtr = qualify $dad_wtr, $package;
    ! $dad_rdr = qualify $dad_rdr, $package;
    ! $dad_err = qualify $dad_err, $package;

    my $kid_rdr = gensym;
    my $kid_wtr = gensym;
    --- 175,183 ----
    $dup_err = ($dad_err =~ s/^[<>]&//);

    # force unqualified filehandles into caller's package
    ! $dad_wtr = qualify $dad_wtr, $package unless fh_is_fd($dad_wtr);
    ! $dad_rdr = qualify $dad_rdr, $package unless fh_is_fd($dad_rdr);
    ! $dad_err = qualify $dad_err, $package unless fh_is_fd($dad_err);

    my $kid_rdr = gensym;
    my $kid_wtr = gensym;
    ***************
    *** 181,200 ****
    # If she wants to dup the kid's stderr onto her stdout I need to
    # save a copy of her stdout before I put something else there.
    if ($dad_rdr ne $dad_err && $dup_err
    ! && fileno($dad_err) == fileno(STDOUT)) {
    my $tmp = gensym;
    xopen($tmp, ">&$dad_err");
    $dad_err = $tmp;
    }

    if ($dup_wtr) {
    ! xopen \*STDIN, "<&$dad_wtr" if fileno(STDIN) != fileno($dad_wtr);
    } else {
    xclose $dad_wtr;
    xopen \*STDIN, "<&=" . fileno $kid_rdr;
    }
    if ($dup_rdr) {
    ! xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != fileno($dad_rdr);
    } else {
    xclose $dad_rdr;
    xopen \*STDOUT, ">&=" . fileno $kid_wtr;
    --- 192,211 ----
    # If she wants to dup the kid's stderr onto her stdout I need to
    # save a copy of her stdout before I put something else there.
    if ($dad_rdr ne $dad_err && $dup_err
    ! && xfileno($dad_err) == fileno(STDOUT)) {
    my $tmp = gensym;
    xopen($tmp, ">&$dad_err");
    $dad_err = $tmp;
    }

    if ($dup_wtr) {
    ! xopen \*STDIN, "<&$dad_wtr" if fileno(STDIN) != xfileno($dad_wtr);
    } else {
    xclose $dad_wtr;
    xopen \*STDIN, "<&=" . fileno $kid_rdr;
    }
    if ($dup_rdr) {
    ! xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != xfileno($dad_rdr);
    } else {
    xclose $dad_rdr;
    xopen \*STDOUT, ">&=" . fileno $kid_wtr;
    ***************
    *** 204,211 ****
    # I have to use a fileno here because in this one case
    # I'm doing a dup but the filehandle might be a reference
    # (from the special case above).
    ! xopen \*STDERR, ">&" . fileno $dad_err
    ! if fileno(STDERR) != fileno($dad_err);
    } else {
    xclose $dad_err;
    xopen \*STDERR, ">&=" . fileno $kid_err;
    --- 215,222 ----
    # I have to use a fileno here because in this one case
    # I'm doing a dup but the filehandle might be a reference
    # (from the special case above).
    ! xopen \*STDERR, ">&" . xfileno($dad_err)
    ! if fileno(STDERR) != xfileno($dad_err);
    } else {
    xclose $dad_err;
    xopen \*STDERR, ">&=" . fileno $kid_err;
  • Barrie Slaymaker at Jun 26, 2000 at 3:13 am

    Frank Tobin wrote:

    + sub xfileno {
    + my ($fh) = @_;
    + return $1 if $fh =~ /^=?(\d+)$/; # deal with $fh just being an fd
    + return fileno $fh;
    Perhaps croak if fileno returns undef?

    - Barrie
  • Ronald J Kimball at Jun 26, 2000 at 3:42 am

    On Sun, Jun 25, 2000 at 07:00:58PM -0500, Frank Tobin wrote:
    + sub xfileno {
    + my ($fh) = @_;
    + return $1 if $fh =~ /^=?(\d+)$/; # deal with $fh just being an fd
    + return fileno $fh;
    + }
    +
    + sub fh_is_fd {
    + return $_[0] =~ /^=?\d+$/;
    + }
    +
    What if $_[0] is "3\n"?

    /\A=?\d+\z/

    Ronald

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupperl5-porters @
categoriesperl
postedJun 25, '00 at 9:29p
activeJun 26, '00 at 3:42a
posts5
users4
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase