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.