See also: The Introduction | Part 1: The Path | Part 2: The Loop | Part 3: The Execution | Part 4: The Interrupt | Part 5: The Dynamic.
When we run a program with run or shell we get a
Proc object. We can redirect in- and output on it.
Let us revisit this command from Part 3: The Execution:
shell 'ls -lR | gzip -9 > ls-lR.gz';
Here it is implement with run and Proc:
my $fh = open :w, :bin, "ls-lR.gz";
my $proc1 = run <ls -lR>, :out;
my $proc2 = run <gzip -9>, :in($proc1.out), :out($fh);
$fh.close;
And as an unreadable one-liner without all the variables (and shown here on two lines to make it somewhat easier to read):
File: run-io2
run <gzip -9>, :in((run <ls -lR>, :out).out),
:out(open :w, :bin, "ls-lR.gz");
This works with in- and ouput for shell as
well, but it is easier to let the shell do it for us (as shown in the example).
See docs.raku.org/type/Proc for more
information about Proc.
We can handle STDERR as well, with :err.
We can catch the output, by calling out on the Proc
object:
> my $proc = run <ls -lR>, :out;
> my $output = $proc.out.slurp(:close);
Note that :close is required, as the filehandle will be left open otherwise.
Except that it isn't really a filehandle, but a
IO.Pipe object:
> my $proc = run <ls -lR>, :out;
> say $proc.out.WHAT;
(Pipe)
See
docs.perl6.org/type/IO::Pipe for more information about IO.Pipe.
WHAT is a Metamethod that gives the type of
the object. See
docs.raku.org/language/mop#WHAT
for more information.
Quoting is normally done with 'single quotes' (which does not interpolate variables) and "double quotes" (which does interpolate them).
We can also use the q/.../ or qq/.../ construct, where
q is the same as single quoting, and qq is the same
as double quoting:
> my $a = 122;
> say q/This is $a/; # -> This is $a
> say qq/This is $a/; # -> This is 122
This quoting construct will execute (as a program) whatever is inside the quotes.
If we use qx, the return value is the output from the program. And
we have no way of getting at the Proc object (and status codes).
> say "** " ~ qx/date/ ~ " **";
** Sa. 11. April 13:43:11 +0200 2020
**
> say "** " ~ qx/date/.chomp ~ " **";
** Sa. 11. April 13:43:11 +0200 2020 **
The shell will complain (to STDOUT) if it doesn't find the program:
> say "** " ~ qx/foo.bar/.chomp ~ " **";
/bin/sh: 1: foo.bar: not found
** **
See
docs.raku.org/language/routine/chomp
for more information about chomp.
The qx version of the «hostname» program looks like this:
print qx/hostname/;
We use print as the «hostname» program has added a newline for us
(and one is enough).
The shell version is shorter:
shell("hostname");
The program handles the output, so we don't even have to do a print.
(If we do, we get the Proc object.)
We can do it the hard way, by capturing the output and printing it ourself:
File: hostname-proc
my $proc = shell "hostname", :out;
my $host = $proc.out.slurp(:close);
print $host;
We can swap shell with run, but it doesn't make a
difference in this case.
qx does not not do variable interpolation. Use qqx
if you require interpolation:
my $cmd = "hostname";
print qqx/$cmd/;
Be very careful if you do this, as you may end up running harmful commands.
It is always a good idea to check for alternatives.
Raku actually supplies the hostname out of the box in the dynamic variable
$*KERNEL:
say $*KERNEL.hostname;
There will be a 7th part «The Promise» in a couple of weeks, and that is a promise.