coreutils
[Top][All Lists]
Advanced

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

Re: Does head util cause SIGPIPE?


From: Assaf Gordon
Subject: Re: Does head util cause SIGPIPE?
Date: Fri, 25 Oct 2019 16:37:40 -0600
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.9.0

Hello,

The question "does head cause SIGPIPE" is seemingly simple,
and the answer is "yes" - but there are some nuances that might
cause unexpected results.

More specifically,
1. The "head" process terminates when all requested
   lines have been printed (e.g. one line with "head -n1").
2. The STDIN of the 'head' process is closed, which corresponds
   to the STDOUT of the preceding process ('find' in your case).
3. *IF* the 'find' process tries to write again to its STDOUT
   (which is now a closed pipe), then a SIGPIPE will be raised
   and 'find' will terminate.

On 2019-10-25 1:56 a.m., Ray Satiro wrote:
Recently I tracked down a delay in some scripts to this line:

find / -name filename* 2>/dev/null | head -n 1
[...]
owner@ubuntu1604-x64-vm:~$ ( trap '' pipe; find / -name initrd* 2>/dev/null | strace -e 'trace=!all' head -n 1)
/initrd.img
+++ exited with 0 +++
(few seconds wait)

In your case,
I can guess that there is only a single file matching your predicate 'initrd*'.
The 'head' indeed terminates, and the pipe is closed.
But if 'find' doesn't find any more matching files, it doesn't
try to print anything more, and SIGPIPE is never raised.

Note the manual page of pipe(7) says:
    "If all file descriptors referring to  the  read
     end  of a pipe have been closed, then a write(2)
     will cause a SIGPIPE signal to be generated for the
     calling process."

So if no further files were found, 'find' continues (slowly scanning
the disk) until it finishes.

Since we only need the first line I can just use find options -print -quit and skip piping to head. But say we needed the first n results, how would I do that with head and get find to terminate rather than continue searching?

That's an interesting question, but perhaps better answered
in address@hidden (although findutils maintainers are also
on this mailing list).

---

There could be other instances where the sending process won't receive SIGPIPE: if the entire output is very small (less than 4096 bytes on
linux, and at least 512 bytes on POSIX systems).

For example, this 'seq' won't be terminated by a signal,
as the entire output is just 21 bytes:

    $ seq 10 | wc -c
    21

    $ seq 10 | head -n1

But this 'seq' will be terminated by a signal:

   $ seq 10000 | wc -c
   48894

   $ seq 10000 | head -n1

---

GNU 'time' can be used to quickly see how a process terminated (with a signal, or a non-zero exit code). It will print a line such as:
   "Command terminated by signal 13"
(signal 13 is SIGPIPE on linux).

   $ \time -p -f "" seq 10000 | head -n1
   1
   Command terminated by signal 13

   $ \time -p -f "" seq 10 | head -n1
   1

And just couple of days ago a new experimental feature
was added to GNU time to allow finer printf-style output
about signals and exit codes:
  https://lists.gnu.org/archive/html/bug-time/2019-10/msg00002.html

---

Lastly,
Recent version of GNU 'env' (from coreutils version 8.31, released on
March 2019) added new command-line options to ignore,block and restore
to default any signal, as a useful alternative to "trap ''",
see:

https://git.savannah.gnu.org/cgit/coreutils.git/commit/?id=95adadd9a420812ddd3f0fc6105f668922a97ae5
and the manual:
  https://www.gnu.org/software/coreutils/env

---

Hope this helps,
 - assaf







reply via email to

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