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 stdmux(1) exits with the I<COMMAND>'s exit status.
25 mux_output=`stdmux command`
26 demux() { local prefix=$1; sed -ne "s/^$prefix//p"; }
27 output_text=`echo "$mux_output" | demux 1`
28 error_text=`echo "$mux_output" | demux 2`
33 use Getopt
::Long qw
/:config no_ignore_case bundling no_getopt_compat/;
49 'o|stdout=s' => \
$FileDesc->{1}->{'prefix'},
50 'e|stderr=s' => \
$FileDesc->{2}->{'prefix'},
51 ) or pod2usage
(-exitval
=>2, -verbose
=>99);
55 pod2usage
(-exitval
=>2, -verbose
=>99);
66 my $nl = index $fdesc->{'buf'}, "\n";
70 my $line = substr $fdesc->{'buf'}, 0, $nl;
71 print $fdesc->{'prefix'}.$line;
73 $fdesc->{'buf'} = substr $fdesc->{'buf'}, $nl;
80 pipe($stdout_r, $stdout_w) or die "$0: pipe: $!\n";
81 pipe($stderr_r, $stderr_w) or die "$0: pipe: $!\n";
84 my $child_pid = fork // die "$0: fork: $!\n";
88 open STDOUT
, '>&', $stdout_w or die "$0: replace stdout: $!\n";
89 open STDERR
, '>&', $stderr_w or die "$0: replace stderr: $!\n";
92 exec {$ARGV[0]} @ARGV;
97 my $child_status = undef;
101 fcntl($stdout_r, F_SETFL
, fcntl($stdout_r, F_GETFL
, 0) | O_NONBLOCK
);
102 fcntl($stderr_r, F_SETFL
, fcntl($stderr_r, F_GETFL
, 0) | O_NONBLOCK
);
108 $FileDesc->{1}->{'fh'} = $stdout_r;
109 $FileDesc->{1}->{'fileno'} = fileno $stdout_r;
110 $FileDesc->{2}->{'fh'} = $stderr_r;
111 $FileDesc->{2}->{'fileno'} = fileno $stderr_r;
118 for my $fd (keys %$FileDesc)
120 vec($fds, $FileDesc->{$fd}->{'fileno'}, 1) = 1 if defined $FileDesc->{$fd}->{'fh'};
125 select($fds, undef, undef, undef);
130 for my $fd (keys %$FileDesc)
132 my $fdesc = $FileDesc->{$fd};
134 if(vec($fds, $fdesc->{'fileno'}, 1) == 1)
136 my $bytes = sysread $fdesc->{'fh'}, $fdesc->{'buf'}, 1024, length $fdesc->{'buf'};
139 process_stream
($fdesc);
143 # this stream is closed.
144 undef $fdesc->{'fh'};
145 # echo last unterminated line (if any)
146 print $fdesc->{'prefix'}.$fdesc->{'buf'} if length $fdesc->{'buf'};
152 waitpid($child_pid, 0);
154 $exit_status = WEXITSTATUS
($child_status);
155 $exit_status = 128 + WTERMSIG
($child_status) if WIFSIGNALED
($child_status);