
$| = 1;

while (1) {
  print "perl% ";
  my $command = <STDIN>;
  last if $command eq '';
  chomp $command;
  my (%command) = parse($command);
  my $pid = fork;
  if (! defined $pid) { print STDERR "Couldn't fork: $!\n" }
  elsif ($pid != 0) { wait }
  else { 
    if (defined $command{stdin}) {
      open STDIN, "<", $command{stdin} 
        or die "Couldn't redirect stdin from $command{stdin}: $!\n";
    }
    if (defined $command{stdout}) {
      open STDOUT, $command{append}, $command{stdout} 
        or die "Couldn't redirect stdout to $command{stdout}: $!\n";
    }
    exec $command{program}, @{$command{args}};
    die "Couldn't exec: $!\n";
  }
}


sub parse {
  my @words = grep $_ =~ /\S/, split /(\s+|<|>>|>)/, $_[0];
  my %d;
  $d{program} = shift @words;
  while (@words) {
    local $_ = shift @words;
    if ($_ eq '<') {
      $d{stdin} = shift @words;
    } elsif ($_ eq '>' || $_ eq '>>') {
      $d{stdout} = shift @words;
      $d{append} = $_;
    } else {
      push @{$d{args}}, $_;
    }
  }
  %d;
}
