7 stdmux - Multiplex the given command's STDOUT and STDERR by prefixing lines
11 stdmux [-o I<STDOUT_PREFIX> | -e I<STDERR_PREFIX>] [--] I<COMMAND> [I<ARGS>]
21 =item -u, --unbuffered
29 stdmux(1) exits with the I<COMMAND>'s exit status.
33 mux_output=`stdmux command`
34 demux() { local prefix=$1; sed -ne "s/^$prefix//p"; }
35 output_text=`echo "$mux_output" | demux 1`
36 error_text=`echo "$mux_output" | demux 2`
42 use Getopt
::Long qw
/:config no_ignore_case bundling no_getopt_compat/;
58 'o|stdout=s' => \
$FileDesc->{1}->{'prefix'},
59 'e|stderr=s' => \
$FileDesc->{2}->{'prefix'},
60 '<>' => sub { unshift @ARGV, @_[0]; die '!FINISH'; },
61 ) or pod2usage
(-exitval
=>2, -verbose
=>99);
65 pod2usage
(-exitval
=>2, -verbose
=>99);
76 my $nl = index $fdesc->{'buf'}, "\n";
80 my $line = substr $fdesc->{'buf'}, 0, $nl;
81 print $fdesc->{'prefix'}.$line;
83 $fdesc->{'buf'} = substr $fdesc->{'buf'}, $nl;
90 pipe($stdout_r, $stdout_w) or die "$0: pipe: $!\n";
91 pipe($stderr_r, $stderr_w) or die "$0: pipe: $!\n";
94 my $child_pid = fork // die "$0: fork: $!\n";
98 open STDOUT
, '>&', $stdout_w or die "$0: replace stdout: $!\n";
99 open STDERR
, '>&', $stderr_w or die "$0: replace stderr: $!\n";
103 exec {$ARGV[0]} @ARGV;
104 my ($errno, $errstr) = (int $!, $!);
105 warn "$0: ${ARGV[0]}: $errstr\n";
110 my $child_status = undef;
114 fcntl($stdout_r, F_SETFL
, fcntl($stdout_r, F_GETFL
, 0) | O_NONBLOCK
);
115 fcntl($stderr_r, F_SETFL
, fcntl($stderr_r, F_GETFL
, 0) | O_NONBLOCK
);
121 $FileDesc->{1}->{'fh'} = $stdout_r;
122 $FileDesc->{1}->{'fileno'} = fileno $stdout_r;
123 $FileDesc->{2}->{'fh'} = $stderr_r;
124 $FileDesc->{2}->{'fileno'} = fileno $stderr_r;
131 for my $fd (keys %$FileDesc)
133 vec($fds, $FileDesc->{$fd}->{'fileno'}, 1) = 1 if defined $FileDesc->{$fd}->{'fh'};
138 select($fds, undef, undef, undef);
143 for my $fd (keys %$FileDesc)
145 my $fdesc = $FileDesc->{$fd};
147 if(vec($fds, $fdesc->{'fileno'}, 1) == 1)
149 my $bytes = sysread $fdesc->{'fh'}, $fdesc->{'buf'}, 1024, length $fdesc->{'buf'};
152 process_stream
($fdesc);
156 # this stream is closed.
157 undef $fdesc->{'fh'};
158 # echo last unterminated line (if any)
159 print $fdesc->{'prefix'}.$fdesc->{'buf'} if length $fdesc->{'buf'};
165 waitpid($child_pid, 0);
167 $exit_status = WEXITSTATUS
($child_status);
168 $exit_status = 128 + WTERMSIG
($child_status) if WIFSIGNALED
($child_status);