From: Peng Yu on
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?

#!/usr/bin/perl

use warnings;
use strict;

open(IN, 'ls <(echo main.txt) |');
foreach (<IN>) {
print
}
From: Alan Curry on
In article <f3faff34-3471-4628-9b7e-6c713b91ce6a(a)a20g2000vbc.googlegroups.com>,
Peng Yu <pengyu.ut(a)gmail.com> wrote:
>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?
>
>#!/usr/bin/perl
>
>use warnings;
>use strict;
>
>open(IN, 'ls <(echo main.txt) |');
>foreach (<IN>) {
> print
>}

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
From: Ben Morrow on

Quoth Peng Yu <pengyu.ut(a)gmail.com>:
> 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?
>
> #!/usr/bin/perl
>
> use warnings;
> use strict;
>
> open(IN, 'ls <(echo main.txt) |');

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)

/var/tmp//sh-np-1275780961

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').

> foreach (<IN>) {
> print
> }

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.

Ben