This program runs a simple program in the background and collects its output. It's possible to interact with child programs as well.

use warnings;
use strict;
use POE qw( Wheel::Run Filter::Line );

# Start the session.  Spawn a simple program, and describe the events
# it will generate as it does things.
sub _start {
  my ($kernel, $heap) = @_[KERNEL, HEAP];
  $heap->{child} = POE::Wheel::Run->new(
    Program => ["/bin/ls", "-1", "/"],    # Program to run.
    StdioFilter  => POE::Filter::Line->new(),    # Child speaks in lines.
    StderrFilter => POE::Filter::Line->new(),    # Child speaks in lines.
    StdoutEvent  => "got_child_stdout",          # Child wrote to STDOUT.
    StderrEvent  => "got_child_stderr",          # Child wrote to STDERR.
    CloseEvent   => "got_child_close",           # Child stopped writing.
  $kernel->sig_child($heap->{child}->PID, "got_sigchld");

# Deal with information the child wrote to its STDOUT.
sub got_child_stdout {
  my $stdout = $_[ARG0];
  print "STDOUT: $stdout\n";

# Deal with information the child wrote to its STDERR.  These are
# warnings and possibly error messages.
sub got_child_stderr {
  my $stderr = $_[ARG0];
  $stderr =~ tr[ -~][]cd;
  print "STDERR: $stderr\n";

# The child has closed its output filehandles.  It will not be sending
# us any more information, so destroy it.
sub got_child_close {
  my $heap = $_[HEAP];
  print "child closed.\n";
  delete $heap->{child};

# Handle SIGCHLD, otherwise the child process will not be reaped.
# Don't do anything significant, but do catch the signal so the child
# process is reaped.
sub got_sigchld {
  print "SIGCHLD reaped.\n";

# A list of functions that will handle the events they're named after.
my @handlers = qw(
  _start got_child_stdout got_child_stderr got_child_close

# Start a session where each event is handled by a function with the
# same name.  Run POE's Kernel (and thus all its sessions) until done.
POE::Session->create(package_states => [main => \@handlers]);
exit 0;