groff
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Groff] Trouble switching to groff, macro gives syntax error...


From: Ralph Corderoy
Subject: Re: [Groff] Trouble switching to groff, macro gives syntax error...
Date: Wed, 16 Sep 2015 13:04:38 +0100

Hi Anton,

> > I'm assuming you know about the SIGPIPE, or EPIPE return from
> > write(2), that occurs when sed closes its stdin, nroff's stdout, and
> > how that ripples back through the pipeline, causing yes(1) to stop?
> 
> No, I don't. This really was my question.  From your answer I see it's
> not trivial.

Oh, it's pretty simple in the simple case.  :-)

    (printf '.pl 1i\n.ll 2i\n'; yes 'a \n%') | nroff | sed 13q

We've two pipes, nroff is reading from one and writing to another.  A
pipe has two ends.  If the writing end of the pipe gets closed then the
reader will see that as end of file, i.e. read(2) returns 0.  That's
what fmt sees:

    $ seq 10 | strace -e read fmt
    ...
    read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n", 4096) = 21
    read(0, "", 4096)                       = 0
    1 2 3 4 5 6 7 8 9 10
    $

But what if the opposite happens?  What if the reading end of the pipe
is closed by the reader?  There's no `end of file' expected by the
writer as it's not what occurs with a normal write(2) to a file.
Instead, the kernel sends a SIGPIPE signal to the process that attempts
to write(2) to a pipe where the reader has closed it.

I can show that by having a Bourne shell attempt to write(2) four bytes,
"foo\n", to its stdout, down a pipe that has already had file descriptor
zero, stdin, closed.  The trap causes a diagnostic on stderr;  that's
still open.

    $ sh -c '(trap "echo sigpipe >&2" PIPE; echo foo)' | <&- 
    sigpipe
    $

signal(7) documents the default behaviour on receiving SIGPIPE is to
terminate;  the process ends.  That's often ideal because it stops the
writer beavering away when the reader has no interest, or ability now
it's closed stdin, to read the writer's output.  No special programming
logic is needed at every point a program may write(2).

Many pipelines make use of this efficiency, and it allows for `endless'
sources of input to be used.  As well as yes(1), there's

    tr -dcs 'a-z \n' ' \n' </dev/urandom

for example.  As long as a later bit of the pipeline closes its stdin,
and that also happens when it exits, then SIGPIPEs will ripple back down
the pipeline, terminating each process.

A process can choose to ignore SIGPIPE;  it will then see write(1)
return -1, error, with errno set to EPIPE.  That was the other
alternative I mentioned.

Note, Python is brain damaged in this regard, so I start my command-line
Python scripts that need to be good Unix subjects with

    signal.signal(signal.SIGPIPE, signal.SIG_DFL)   # Sanity restored.

Cheers, Ralph.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]