I recently had to deal with some strange effects around process-pipes:
The one bit where I might have left the "beaten path" is, that the sub-process writes to both stdout and stderr, but both shall be
captured from the pipe, so there is a "2>@1" redirection involved.
Not sure, if this is relevant, though.
Case 1:
the process writes to stdout, closes stdout, then writes something
to stderr, and finally exits. (stderr only gets closed by exit.)
Observation:
Once the sub-process closes stdout, it can still write to stderr,
but that isn't seen by tclsh. From standard Unix experience, I
would have expected that the subprocess would have two fd for
stdout and stderr that just to to the same channel. closing one
of them would leave the channel intact.
According to "truss -ff ..." output, the child writes to stdout,
closes stdout, writes to stderr and exits, but tclsh only reads
what the subprocess wroe before the close of stdout. Everything
afterwards just wasn't received by the tcl script-process.
(actually, the child process was a tcl-script as well.)
I could workaround it, by avoiding the explicit close for stdout.
Case 2:
the child process writes data on stderr and stdout, and eventually
exits with a non-zero exit code.
Case 3:
I do an "exec hd $filename | head" to get the first 10 lines
of hexdump of a given file.
On shell (bash), hd foo | head works fine. No one sees, that
hd gets a broken pipe, once head has finished.
in tcl, however, exec throws an error, for "hd"'s exit-code.
Is there a way to tell exec to ignore exitcodes of all but the
last command of a pipe line?
Andreas Leitgeb <avl@logic.at> wrote:
I recently had to deal with some strange effects around process-pipes:I suspect it is relevant.
The one bit where I might have left the "beaten path" is, that the
sub-process writes to both stdout and stderr, but both shall be
captured from the pipe, so there is a "2>@1" redirection involved.
Not sure, if this is relevant, though.
Case 1:
the process writes to stdout, closes stdout, then writes something
to stderr, and finally exits. (stderr only gets closed by exit.)
Observation:
Once the sub-process closes stdout, it can still write to stderr,
but that isn't seen by tclsh.
I could workaround it, by avoiding the explicit close for stdout.
The equivalent Bash operator "2>&1" is a file descriptor duplication operation. It means to take the current file descriptor that is fd1
(stdout) and duplicate it to be fd2 (stderr). The result is that while
the process stdout and stderr channels open in the standard positions,
both refer to the same "destination" file descriptor.
So closing either one is also a close of the other.
Case 3:
I do an "exec hd $filename | head" to get the first 10 lines
of hexdump of a given file.
in tcl, however, exec throws an error, for "hd"'s exit-code.
Is there a way to tell exec to ignore exitcodes of all but the
last command of a pipe line?
Not so elegant, but it does suppress the error:
exec bash -c "hd $filename || echo -n" | head
* Andreas Leitgeb <avl@logic.at>
| I recently had to deal with some strange effects around process-pipes:
| The one bit where I might have left the "beaten path" is, that the
| sub-process writes to both stdout and stderr, but both shall be
| captured from the pipe, so there is a "2>@1" redirection involved.
| Not sure, if this is relevant, though.
As Rich pointed out, it is relevant for case 1. As an alternative you
could create a pipe and redirect stderr to that, see chan(n) for details (this case is explicitely noted there)
https://www.tcl-lang.org/man/tcl/TclCmd/chan.htm#M29
chan pipe
Creates a standalone pipe whose read- and write-side channels are
returned as a 2-element list, >
| Case 2:
| the child process writes data on stderr and stdout, and eventually
| exits with a non-zero exit code.
| Observation:
| tcl notices the eof on the channel, does a "NOHANG"-wait to see
| for the child process' exit code, but doesn't hit it.
Do you by any chance have the channel configured non-blocking?
| Case 3:
| I do an "exec hd $filename | head" to get the first 10 lines
| of hexdump of a given file.
If you have control over 'hd' source code, you could make it silently
ignore SIGPIPE... other than that, again see Rich's suggestion.
in bash:
$ bash -c 'echo a;echo b >&2;exec>/dev/null;echo c >&2' |& sed 's/^/x/'
xa
xb
xc
$
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 297 |
Nodes: | 16 (0 / 16) |
Uptime: | 00:14:48 |
Calls: | 6,669 |
Calls today: | 1 |
Files: | 12,216 |
Messages: | 5,338,431 |