6
$ pdfgrep -R -i spark . | less &
$ pdfgrep -R -i spark . &

$ jobs
[3]-  Stopped                 pdfgrep -R -i spark . | less
[4]   Running                 pdfgrep -R -i spark . &
  1. Why would the one with | less be stopped, while the other one without it is running?

    The stopped backgrounded job doesn't read from stdin. So that can't be the reason.

  2. The reason that I background the jobs is that I can do something else in the same terminal session.

    The reason that I pipe to less is because I don't want the output to stdout messes up the screen of my terminal session when I am doing something else.

    Is there some way to achieve the two goals above? I slightly prefer not saving output to a file over saving output to a file, because it takes a little more to remember the file, read and delete them.

Thanks.

Tim
  • 101,790

3 Answers3

17

Let's look more closely at what's happening to less:

$ pdfgrep -R -i spark . | strace less &
[...]
open("/dev/tty", O_RDONLY|O_LARGEFILE)  = 3
ioctl(3, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGTTOU {si_signo=SIGTTOU, si_code=SI_KERNEL} ---
--- stopped by SIGTTOU ---

Job control restricts the processes in a background job from performing certain operations on the controlling terminal.

  • If a background process tries to read from the terminal, it will be sent a SIGTTIN signal, which typically stops (pauses) the process.

  • If a background process tries to set a terminal's parameters, it will be sent a SIGTTOU signal, which also typically stops the process. That's what is happening here with the TCSETSW ioctl. The less program tries to put the terminal into raw mode soon after it starts, even before it knows whether it has anything to display.

    There is a good reason for this: you don't want a background job asynchronously changing your terminal so that, for example, raw mode is on and echo is off. (A background process can get terminal parameters with the TCGETS ioctl without being stopped - see the listing above.)

  • If a background process tries to write to the terminal and the terminal has the tostop flag set, it will be sent the SIGTTOU signal.

You probably don't have the tostop flag set (run stty -a to check). If you don't, a background command like pdfgrep -R -i spark . & that doesn't change any terminal settings will be able to write to your terminal whenever it tries.

You also wrote:

The reason that I pipe to less is because I don't want the output to stdout messes up the screen of my terminal session when I am doing something else

The less program is ultimately going to send output to the terminal, one screenful at a time. If you run stty tostop before pdfgrep | less &, or before pdfgrep &, then they will only output to your terminal when they are in the foreground.

Mark Plotnick
  • 25,413
  • 3
  • 64
  • 82
6

To answer your second question: I use screen(1) to multiplex many commands through one tty-like device.

There is at least one alternative, tmux(1) and a simplifying wrapper for both, byobu(1).

5

less is trying to interact with (output to) the TTY, but since it's running as a background job, it has no TTY to write to. The pdfgrep utility, on the other hand, writes to standard output.

On my system, I get the slightly more descriptive output

$ cat ~/.profile | less &
[1] 51758 67354
$
[1] + Done                 cat ~/.profile |
      Stopped (tty output) less

In this simple example, cat finishes sending my .profile to less, but less is unable to display it since it's a background job. Hence the Stopped (tty output) less message.

The less process is still running though. It's only temporarilly stopped. To switch to it, use fg %1 (the number corresponds to the job number reported in square brackets in the "stopped" message, and it should also have been reported when you started the job).


Related: top, top&, top & commands in linux

Kusalananda
  • 333,661
  • 2
    Thanks. But I remember a background job can output to stdout without being paused, and it is stopped only when trying to read from stdin. – Tim Oct 08 '17 at 14:35
  • cat ~/.profile also outputs to tty too, but cat ~/.profile & won't stop it. – Tim Oct 08 '17 at 14:38
  • 1
    @Tim What makes you think less sends its output to its standard output? – Kusalananda Oct 08 '17 at 14:38
  • 2
    @Tim No, cat outputs to standard output. less needs a controlling terminal. It's an interactive program. – Kusalananda Oct 08 '17 at 14:39
  • Thanks. Is there any way for my question in part 2? – Tim Oct 08 '17 at 14:47
  • @Tim Did so now. You can switch to less with fg %3 (in this example). – Kusalananda Oct 08 '17 at 14:51
  • Is it possible to keep it running in background so that I can do something else? – Tim Oct 08 '17 at 15:18
  • @Tim You may avoid putting it in the foreground at all, or if you do, just press Ctrl+Z to suspend it again. – Kusalananda Oct 08 '17 at 15:25
  • Thanks. "less is trying to interact with (output to) the TTY, but since it's running as a background job, it has no TTY to write to. The pdfgrep utility, on the other hand, writes to standard output." "cat outputs to standard output. less needs a controlling terminal. It's an interactive program." What is the difference between "outputs to standard output" and "needs a controlling terminal and is an interactive program"? Is the latter equal to "outputs to standard output" plus "inputs from standard input"? Or is the output part of the latter still different from the former? – Tim May 05 '18 at 10:34
  • @Tim Yes, different. less writes directly to the tty. Since the tty is connected to the foreground process, not to less, it has to stop until it's "handed back" to less again (using fg). Writing to standard output does not have that restriction, unless it happens to be redirected to the tty (see for example cat >$(tty) & which will have the same issue as less has). – Kusalananda May 05 '18 at 12:02