Bash: pause and resume execution with space

I am running a code that produces a large amount of output for over an hour. At runtime, I log my output to a file using tee

. However, the huge amount of output that is still being sent to my terminal is a bit cumbersome, so I made a small function ShowLastLines

where I can connect my output that will only show the last 15 lines of output and realtime updates.

This is the script:

function ShowLastLines {
    numberoflines=15
    i=1
    while read var
    do
        echo $var
        if [ $i -gt $numberoflines ]
        then
            tput sc && tput cuu $(( $numberoflines +1 )) && tput dl 1 && tput rc && tput cuu 1
        fi
        (( i++ ))
    done
}

      

In practice, I use it like this:

( long code ) 2>&1 | tee output.log | ShowLastLines

      

This works well as expected, however I would like to add one more functionality, namely, I want to pause the output (in ShowLastLines

, of course, not in the original execution) when I am in a space (for example, for researching some in detail, I noticed), and let it continue when I hit the gap again (where it catches up with the execution exit).

I've tried several things but still haven't succeeded. I suppose this is possible by putting the standard input in non-blocking mode using stty

(as in this thread ):

stty -echo -icanon time 0 min 0

      

but I am unable to reconcile it with the existing one read

.

Important note: I am on an AFS cluster, so I cannot access the log file (written tee

) until the computation is complete due to the way synchronization is implemented between different machines (I know it would otherwise be easier to use tail -f

in the log file ).

Ps: The most useful implementation would be that when the exit is paused by pressing the spacebar, one can scroll up the exit to also show the lines earlier. Any suggestions are appreciated, but I understand that this probably requires a completely different implementation that can add a lot of computational overhead, so I am reasonably happy with a solution that gives a simple pause with a space.

+3


source to share


1 answer


This is probably best done with a real program, using select()

to read the input from the pipe and the user at the same time.

But in a Bash script, you can use read

with a small timeout to check if the user pressed a key:

buf() {
    stty -echo < /dev/tty
    while read line ; do
        echo "$line"
        if read -n1 -t0.0001 -u3 3</dev/tty ; then 
            echo paused.
            read -n1 -u3 3</dev/tty
        fi
    done
    stty echo < /dev/tty
}

      



read -n1

will not wait for the whole line, but will return immediately after receiving a character. We need read

from /dev/tty

(stderr can also be executed) since we expect the incoming stream from stdin as in somecmd | buf

.,

The disadvantage here is that if you stop the output for too long, the pipeline will stall and stop the process producing the output. You can work around this by using pv

(say ...| pv -qB 64k |...

) in a pipeline to act as a buffer. Although viewing the output that was sent during the pause of reading was somewhat difficult.

As mentioned in the comments, you can also use terminal emulator buffering for this. This will have the same disadvantage that stopping the exit for too long will stop the writing side of the pipe again.

+2


source







All Articles