using bash process substitution in perl pipe?

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View

I want to use bash instead of sh because I need the process
substitution. But by default perl use sh instead of bash. Is there a
way to let perl use bash?


use warnings;
use strict;

open(IN, 'ls <(echo main.txt) |');
foreach (<IN>) {

Re: using bash process substitution in perl pipe?

Quoted text here. Click to load it

call bash -c 'your command' explicitly, like this:

  open IN, '-|', $shell, '-c', $cmd

Where $shell is 'bash' or '/usr/bin/bash' or something else that names the
shell you want, and $cmd is the 'ls <(echo main.txt)' string

Alan Curry

Re: using bash process substitution in perl pipe?

Quoted text here. Click to load it

This is probably not what you want here. This will give output like (on
my system, for some reason, bash doesn't use /dev/fd)


In this particular case I suspect you just want backticks:

    open my $IN, 'ls $(echo main.txt) |';

You should also be checking the return value of open, or using autodie.
Yes, even in examples, as otherwise people will assume you don't know
that (unless you say something like 'error checking omitted').

Quoted text here. Click to load it

Alan Curry has already posted the simple answer (use bash explicitly,
instead of allowing two-arg open to default to sh). A more portable
solution that doesn't require bash (but does require a /dev/fd
directory) is to do the conversion yourself:

    use autodie;    # easier than checking every call
    use Fcntl;

    sub devfd {
        open my $FD, @_;

        # clear the close-on-exec flag, so the file stays open in the
        # child process
        my $fl = fcntl $FD, F_GETFD, 0;
        fcntl $FD, F_SETFD, ($fl & ~FD_CLOEXEC);

        # the files in /dev/fd (on systems that have that directory) are
        # magic, and opening them will return a dup of an existing file
        # descriptor
        return "/dev/fd/" . fileno $FD;

    my $echo = devfd "-|", qw/echo main.txt/;
    open my $IN, "-|", "ls", $echo;

It's also possible to do this with named pipes (which is what bash
apparently does on my system, even though I've got a perfectly good
/dev/fd directory) but this is a little harder. Apart from creating the
pipe with mkfifo, you have to manually fork/exec the first child so you
can point its stdout at the pipe, and you need a SIGCHILD handler to
clean up the fifo when you've finished with it.


Site Timeline