J
John Kelly
The Camel book, 16.3.1. Anonymous Pipes says:
and 29.2.104. open says
I have a script that traps the standard output of any command passed in
as args to the script. My piped open uses 2>&1 to grab stderr as well
as stdout. I thought > was a shell metacharacter so I expected to see
/bin/sh between my script and the trapped command when doing ps ax. But
in many cases, Perl runs the trapped command directly, without needing
/bin/sh.
You can see that by running the script like this:
../myscript sleep 10
and then doing a ps ax before the sleep ends. Is the book wrong, or I
am I missing something? Here is the script:
#!/usr/bin/perl
# Define author
# John Kelly, July 28, 2010
# Define copyright
# Copyright John Kelly, 2010. All rights reserved.
# Define license
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this work except in compliance with the License.
# You may obtain a copy of the License at:
# http://www.apache.org/licenses/LICENSE-2.0
# Define symbols and (words)
# OT ........... Output Trap
# bas0 ......... basename of $0
# binx ......... binary executable
# tt ........... temporary time
use strict;
use FileHandle;
use File::Basename;
use POSIX qw (strftime);
STDOUT->autoflush (1);
STDERR->autoflush (1);
my $bas0 = basename ($0);
my $binx;
unless ($binx = shift @ARGV) {
print "Usage: ", $bas0, " binary.executable [args]\n";
exit 1;
}
my $basx = basename ($binx);
if (!defined (open OT, "$binx @ARGV 2>&1 |")) {
printf "%s -> %s: failure starting %s: $!\n", &tt, $bas0, $binx;
exit 1;
}
while (<OT>) {
/^\s*$/ && next;
printf "%s -> %s: ", &tt, $basx;
print $_;
}
if (!(close OT) && $!) {
printf "%s -> %s: failure closing OT: $!\n", &tt, $bas0;
} else {
if ($? & 127) {
printf "%s -> %s: %s signal %d, %s coredump\n", &tt, $bas0, $basx,
($? & 127), ($? & 128) ? 'with' : 'without';
} else {
printf "%s -> %s: %s exit value %d\n", &tt, $bas0, $basx, $? >> 8;
}
}
sub tt {
strftime "%a %b %e %H:%M:%S %Z %Y", localtime;
}
Perl uses your default system shell (/bin/sh on Unix) whenever a pipe
command contains special characters that the shell cares about. If
you're only starting one command, and you don't need--or don't want--to
use the shell, you can use the multi-argument form of a piped open ...
... But then you don't get I/O redirection, wildcard expansion, or
multistage pipes, since Perl relies on your shell to do those.
and 29.2.104. open says
Any pipe command containing shell metacharacters such as wildcards or
I/O redirections is passed to your system's canonical shell (/bin/sh on
Unix), so those shell-specific constructs can be processed first. If no
metacharacters are found, Perl launches the new process itself without
calling the shell.
I have a script that traps the standard output of any command passed in
as args to the script. My piped open uses 2>&1 to grab stderr as well
as stdout. I thought > was a shell metacharacter so I expected to see
/bin/sh between my script and the trapped command when doing ps ax. But
in many cases, Perl runs the trapped command directly, without needing
/bin/sh.
You can see that by running the script like this:
../myscript sleep 10
and then doing a ps ax before the sleep ends. Is the book wrong, or I
am I missing something? Here is the script:
#!/usr/bin/perl
# Define author
# John Kelly, July 28, 2010
# Define copyright
# Copyright John Kelly, 2010. All rights reserved.
# Define license
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this work except in compliance with the License.
# You may obtain a copy of the License at:
# http://www.apache.org/licenses/LICENSE-2.0
# Define symbols and (words)
# OT ........... Output Trap
# bas0 ......... basename of $0
# binx ......... binary executable
# tt ........... temporary time
use strict;
use FileHandle;
use File::Basename;
use POSIX qw (strftime);
STDOUT->autoflush (1);
STDERR->autoflush (1);
my $bas0 = basename ($0);
my $binx;
unless ($binx = shift @ARGV) {
print "Usage: ", $bas0, " binary.executable [args]\n";
exit 1;
}
my $basx = basename ($binx);
if (!defined (open OT, "$binx @ARGV 2>&1 |")) {
printf "%s -> %s: failure starting %s: $!\n", &tt, $bas0, $binx;
exit 1;
}
while (<OT>) {
/^\s*$/ && next;
printf "%s -> %s: ", &tt, $basx;
print $_;
}
if (!(close OT) && $!) {
printf "%s -> %s: failure closing OT: $!\n", &tt, $bas0;
} else {
if ($? & 127) {
printf "%s -> %s: %s signal %d, %s coredump\n", &tt, $bas0, $basx,
($? & 127), ($? & 128) ? 'with' : 'without';
} else {
printf "%s -> %s: %s exit value %d\n", &tt, $bas0, $basx, $? >> 8;
}
}
sub tt {
strftime "%a %b %e %H:%M:%S %Z %Y", localtime;
}