Mario Carneiro
Mario Carneiro

Reputation: 1693

Quit less when pipe closes

As part of a bash script, I want to run a program repeatedly, and redirect the output to less. The program has an interactive element, so the goal is that when you exit the program via the window's X button, it is restarted via the script. This part works great, but when I use a pipe to less, the program does not automatically restart until I go to the console and press q. The relevant part of the script:

while :
do
    program | less
done

I want to make less quit itself when the pipe closes, so that the program restarts without any user intervention. (That way it behaves just as if the pipe was not there, except while the program is running you can consult the console to view the output of the current run.)

Alternative solutions to this problem are also welcome.

Upvotes: 1

Views: 1056

Answers (3)

neils
neils

Reputation: 11

You may try to kill the process group program and less belong to instead of using kill and lsof.

#!/bin/bash

trap 'kill 0' EXIT

while :
do
   # script command gives sh -c own process group id (only sh -c cmd gets killed, not entire script!)
   # FreeBSD script command
   script -q /dev/null sh -c '(trap "kill -HUP -- -$$" EXIT; echo hello; sleep 5; echo world) | less -E -c'
   # GNU script command
   #script -q -c 'sh -c "(trap \"kill -HUP -- -$$\" EXIT; echo hello; sleep 5; echo world) | less -E -c"' /dev/null
   printf '\n%s\n\n' "you now may ctrl-c the program: $0" 1>&2
   sleep 3
done

Upvotes: 1

chepner
chepner

Reputation: 531798

Instead of exiting less, could you simply aggregate the output of each run of program?

while :
do
    program
done | less

Having less exit when program would be at odds with one useful feature of less, which is that it can buffer the output of a program that exits before you finish reading its output.


UPDATE: Here's an attempt at using a background process to kill less when it is time. It assumes that the only program reading the output file is the less to kill.

while :
do
    ( program > /tmp/$$-program-output; kill $(lsof -Fp | cut -c2-) ) &
    less /tmp/$$-program-output
done

program writes its output to a file. Once it exits, the kill command uses lsof to find out what process is reading the file, then kills it. Note that there is a race condition; less needs to start before program exists. If that's a problem, it can probably be worked around, but I'll avoid cluttering the answer otherwise.

Upvotes: 5

shellter
shellter

Reputation: 37298

While I agree with chepner's suggestion, if you really want individual less instances, I think this item for the man page will help you:

   -e or --quit-at-eof
          Causes less to automatically exit the second time it reaches end-of-file.  By  default,
          the only way to exit less is via the "q" command.

   -E or --QUIT-AT-EOF
          Causes less to automatically exit the first time it reaches end-of-file.

you would make this option visible to less in the LESS envir variable

export LESS="-E"
while : ; do
    program | less
done

IHTH

Upvotes: 0

Related Questions