class Proc

Running process (filehandle-based interface)

class Proc {}

Proc is a representation of an invocation of an external process. It provides access to the input, output and error stream as well as the exit code. It is typically created through the run subroutine:

my $proc = run 'echo''Hallo world':out;
my $captured-output = $proc.out.slurp: :close;
say "Output was $captured-output.perl()";       # OUTPUT: «Output was "Hallo world\n"␤» 

Piping several commands is easy too. To achieve the equivalent of the pipe echo "Hello, world" | cat -n in Perl 6, and capture the output from the second command, you can do

my $p1 = run 'echo''Hello, world':out;
my $p2 = run 'cat''-n':in($p1.out), :out;
say $p2.out.get;

You can also feed the :in pipe directly from your program, by setting it to True, which will make the pipe available via .in method on the Proc:

my $p = run "cat""-n":in:out;
$ "Hello,\nworld!";
say $p.out.slurp: :close;
# OUTPUT: «1  Hello,␤ 
#          2  world!␤» 

In order to capture the standard error :err can be supplied:

my $p = run "ls""-l"".""qqrq":out:err;
my $captured-output = $p.out.slurp: :close;
my $captured-error  = $p.err.slurp: :close;
my $exit-code       = $p.exitcode;

Note: Versions of Rakudo older than 2017.04 do not have .slurp available on IO::Pipe objects; use .slurp-rest instead.

Use Proc::Async for non-blocking operations.


method new

method new(Proc:U:
        :$in = '-',
        :$out = '-',
        :$err = '-',
        Bool :$bin = False,
        Bool :$chomp = True,
        Bool :$merge = False,
        Str:D :$enc = 'UTF-8',
        Str:D :$nl = "\n",
    --> Proc:D)
sub shell(
        :$in = '-',
        :$out = '-',
        :$err = '-',
        Bool :$bin = False,
        Bool :$chomp = True,
        Bool :$merge = False,
        Str:D :$enc = 'UTF-8',
        Str:D :$nl = "\n",
        :$cwd = $*CWD,
        Hash() :$env = %*ENV
    --> Proc:D)

new creates a new Proc object, whereas run or shell create one and spawn it with the command and arguments provided in @args or $cmd, respectively.

$in, $out and $err are the three standard streams of the to-be-launched program, and default to "-" meaning they inherit the stream from the parent process. Setting one (or more) of them to True makes the stream available as an IO::Pipe object of the same name, like for example $proc.out. You can set them to False to discard them. Or you can pass an existing IO::Handle object (for example IO::Pipe) in, in which case this handle is used for the stream.

Please bear in mind that the process streams reside in process variables, not in the dynamic variables that make them available to our programs. Thus, modifying the dynamic filehandle variables (such as $*OUT) inside the host process will have no effect in the spawned process, unlike $*CWD and $*ENV, whose changes will be actually reflected in it.

my $p-name = "/tmp/program.p6";
my $program = Q:to/END/; 
    #!/usr/bin/env perl6
    $*OUT.say( qq/\t$*PROGRAM: This goes to standard output/ );
spurt $p-name$program;
$*OUT.put: "1. standard output before doing anything weird";
    temp $*OUT = open '/tmp/out.txt':w;
    $*OUT.put: "2. temp redefine standard output before this message";
    shell"perl6 $p-name" ).so;
$*OUT.put: "3. everything should be back to normal";
# 1. standard output before doing anything weird 
#     /tmp/program.p6: This goes to standard output 
# 3. everything should be back to normal 
# /tmp/out.txt will contain: 
# 2. temp redefine standard output before this message 

This program shows that the program spawned with shell is not using the temporary $*OUT value defined in the host process (redirected to /tmp/out.txt), but the initial STDOUT defined in the process.

$bin controls whether the streams are handled as binary (i.e. Blob object) or text (i.e. Str objects). If $bin is False, $enc holds the character encoding to encode strings sent to the input stream and decode binary data from the output and error streams.

With $chomp set to True, newlines are stripped from the output and err streams when reading with lines or get. $nl controls what your idea of a newline is.

If $merge is set to True, the standard output and error stream end up merged in $proc.out.

sub run

Defined as:

sub run(
    *@args ($*@),
    :$in = '-',
    :$out = '-',
    :$err = '-',
    Bool :$bin = False,
    Bool :$chomp = True,
    Bool :$merge = False,
    Str:D :$enc = 'UTF-8',
    Str:D :$nl = "\n",
    :$cwd = $*CWD,
    Hash() :$env = %*ENV
--> Proc:D)

Runs an external command without involving a shell and returns a Proc object. By default, the external command will print to standard output and error, and read from standard input.

run 'touch''>foo.txt'# Create a file named >foo.txt 
run <<rm >foo.txt>># Another way to use run, using word quoting for the 
                     # arguments 

If you want to pass some variables you can still use < >, but try to avoid using « » as it will do word splitting if you forget to quote variables:

my $file = --my arbitrary filename;
run touch--$file;  # RIGHT 
run <touch -->$file;     # RIGHT 
run «touch -- "$file"»;    # RIGHT but WRONG if you forget quotes 
run «touch -- $file»;      # WRONG; touches ‘--my’, ‘arbitrary’ and ‘filename’ 
run touch$file;        # WRONG; error from `touch` 
run «touch "$file"»;       # WRONG; error from `touch` 

Note that -- is required for many programs to disambiguate between command-line arguments and filenames that begin with hyphens.

A sunk Proc object for a process that exited unsuccessfully will throw. If you wish to ignore such failures, simply use run in non-sink context:

run 'false';     # SUNK! Will throw 
run('false').so# OK. Evaluates Proc in Bool context; no sinking 

If you want to capture standard output or error instead of having it printed directly you can use the :out or :err arguments respectively, which will make them available using the Proc.out method:

my $proc = run 'echo''Perl 6 is Great!':out:err;
$proc.out.slurp(:close).say# OUTPUT: «Perl 6 is Great!␤» 
$proc.err.slurp(:close).say# OUTPUT: «␤» 

You can use these arguments to redirect them to a filehandle, thus creating a kind of pipe:

my $ls-alt-handle = open :w'/tmp/cur-dir-ls-alt.txt';
my $proc = run "ls""-alt":out($ls-alt-handle);
# (The file will contain the output of the ls -alt command) 

These argument are quite flexible and admit, for instance, handles to redirect them. See Proc and Proc::Async for more details.

See also new for more examples.

method sink

method sink(--> Nil)

When sunk, the Proc object will throw X::Proc::Unsuccessful if the process it ran exited unsuccessfully.

method spawn

method spawn(*@args ($*@), :$cwd = $*CWDHash() :$env = %*ENV --> Bool:D)

Runs the Proc object with the given command, argument list, working directory, and environment.

method shell

method shell($cmd:$cwd = $*CWD:$env --> Bool:D)

Runs the Proc object with the given command and environment which are passed through to the shell for parsing and execution. See IO::shell for an explanation of which shells are used by default in the most common operating systems.

method command

method command(Proc:D: --> List:D)

The command method is an accessor to a list containing the arguments that were passed when the Proc object was executed via spawn or shell or run.

method pid

method pid(Proc:D:)

Returns the $*PID value of the process if available, or Nil.

method exitcode

method exitcode(Proc:D: --> Int:D)

Returns the exit code of the external process, or -1 if it has not exited yet.

method signal

method signal(Proc:D:)

Returns the signal number with which the external process was killed, or 0 or an undefined value otherwise.

Type Graph

Type relations for Proc
perl6-type-graph Proc Proc Any Any Proc->Any Mu Mu Any->Mu

Expand above chart