less
less copied to clipboard
Make it possible to leave "follow forever" mode without pressing Ctrl+C
When piping the output of a long running process to less, the follow forever (F
) command is very useful for keeping the freshest content on the screen, but unfortunately there doesn't seem to be a way to leave follow mode without also stopping the process producing output (CtrlC).
Would it be possible to add a keyboard shortcut for stopping follow forever mode without affecting other processes in the pipe?
(I suspect this is impossible, or at least extremely difficult, but it doesn't hurt to ask)
This is partially related to #6.
I made an attempt at this using select() but did not come up with a working solution. I abandoned the effort for now but saved my results in the alt-intr-char branch for future reference.
Related to #62.
I made an attempt at this using select() but did not come up with a working solution. I abandoned the effort for now but saved my results in the alt-intr-char branch for future reference.
I tried with select
too but it wasn't effective. What about the pool
solution I proposed #6?
Back in May 2019 you seemed to be reluctant to adopt select
/poll
, but if you're OK with select
, why not pool
'
less
is a tool people use interactively, if there's a slightly different behavior across operating systems people will go "oh well...". It's not like we're breaking the portability of any script/piece of code out there.
Well, poll and select perform very similar functionality, and it's not immediately clear to me that it would be any easier to implement using poll vs. select. In the Linux kernel, at least, both poll and select use the same mechanism (they both call f_op->poll on the file). In what way do you think that using poll would be better than select?
It has been a while, but the issue with select
for me was that, when a pipe is closed, it is notified among file descriptors that can be read, readfds
, while I'd expect it to appear among exceptfds
.
On the other hand, with poll
, I was able to detect quite reliably when a pipe was being closed using POLLERR
and POLLHUP
.
man 2 poll
is pretty explicit:
POLLERR Error condition (only returned in revents; ignored in events). This bit is also set for a file descriptor referring to the write end of a pipe when the read end has been closed. POLLHUP Hang up (only returned in revents; ignored in events). Note that when reading from a channel such as a pipe or a stream socket, this event merely indicates that the peer closed its end of the channel. Subsequent reads from the channel will return 0 (end of file) only after all outstanding data in the channel has been consumed.
Or maybe I'm missing something and you tried something different with select
.
Maybe we can move this discussion on #6.
Related unix.stackexchange.com question Is there any way to exit “less” follow mode without stopping other processes in pipe? with answers giving workarounds using shell features to supress ctrl+c propagation across processes involved in a pipe.
I do not see what is difficult there. At least in Bash shell you could put the reading process in background and wait for keypress like this:
cat /dev/urandom | tr -cd 'a-zA-Z0-9' & read -rn1; kill $!
You could pipe some appending input for less
like this
{ cat /dev/urandom | tr -cd 'a-zA-Z0-9' & } | less +F
Though I do not understand why it writes only a screen of text without user interaction; Ctrl + C, F helps.
Though I do not understand why it writes only a screen of text without user interaction; Ctrl + C, F helps.
Yes, that's strange. @gwsw Any thoughts on the possible reason for this behaviour?
In the second example you are piping a string of alphanumerics with no newlines into less. In other words, the file is one infinitely long line. Less doesn't handle a case like that well; it expects lines to be separated by newlines.
As of 5bf862fde4a33ce4a602f369a0c3cb430c883a12, you should be able to exit F mode with control-X, in environments where poll() is supported.
Nice!
So Ctrl + X
interrupts following, right?
This is helpful under certain circumstances, but I've to say that it doesn't help me with the most annoying issue I have: when you're at the end of the stream and you just want to be able to press arrow up and scroll up. Before, I had to press Ctrl + C
to kill an (already dead) process, now I can press Ctrl + X
, but it's not a real improvement in usability.
Since we use poll
, adding this extra feature would be great.
The original request in this issue was to provide a way to exit F mode without terminating other processes in a pipe, which the ^X achieves. It sounds like you're asking for something different, or further, which is to avoid the need to enter a special interrupt character at all, but just allow any keypress to interrupt the read, and then get interpreted as a command. Am I understanding correctly? So your idea would just save one keypress in this situation?
Yes, but my idea would be was to do this only once we can detect that the input pipe is closed. But, yes, I guess that interrupting follow mode on any key press, no matter the status of the input pipe, would work too, despite being a bit more of a radical approach.
Ok, I understand what you are saying and I agree. I will continue discussion in #6.
Does this help to solve #62? Why not use q as shortcut?
The technique used to solve #49 might be usable to solve #62, but the current implementation does not solve #62, so I am reopening that issue.
I prefer to use ^X rather than q to exit follow mode because of the potential for accidentally quitting less. If you're in follow mode and you press q to exit, and the screen does not refresh immediately because of system load or network lag, you might hit q again, and then find that you've unexpectedly exited less when both q's are processed.
What happens with the stdout from the pipe once F mode is left? Is it buffered? And can one resume F mode (and then get the output that happened in the meantime)?
@calestyo It is buffered and you get output that happened in the meantime :)
@calestyo It's buffered until it's not due to the limited size of pipe's buffer – see How big is the pipe buffer?
@gwsw Sorry for bothering you, I was just wondering which release this feature (^X) was released in? :slightly_smiling_face: I'm on Arch Linux with less 590
, and I noticed that ^X doesn't seem to work.
According to https://github.com/gwsw/less/blob/22e4af5cccbfab633000c7d610f868a868ad6e1a/NEWS#L114 this should have been released in 581 - maybe you don't get HAVE_POLL
set in configure in your environment?
Yes, ^X should be supported in less-590, but it requires the OS to support poll(). If you built less yourself, you can check the definition of HAVE_POLL in defines.h to see whether less thinks the OS has poll(). If HAVE_POLL is set, another more disturbing possibility is that the OS supports poll() but it doesn't work correctly. This is the case in MacOS. I don't know much about Arch Linux so I don't know what support there is for poll().
I tried building from the latest master branch.
defines.h
includes:
/* Define to 1 if you have the `poll' function. */
#define HAVE_POLL 1
Pressing Ctrl+X still has no effect. I tried this in both Alacritty and xfce4-terminal, to rule out any terminal emulator keybindings eating the Ctrl+X.
I'm testing with this command:
$ tail -c +0 -f defines.h | ./less
When I press Ctrl+X, nothing happens. Does this work for you?
You are correct that this does not work. Less checks for a ctrl-X keypress just before each read() from the input file. While less is stuck in a blocked read, it cannot see any keys from the terminal. So a case like this would work
i=1; while :; do echo $i; sleep .1; let i=$i+1; done | less
But if the pipe is producing no data ctrl-X won't work.
I think fixing this would require using poll() on the input pipe before each read to confirm that there is data ready to be read. I've done a little work on this but it's not trivial (in particular I haven't found a good way to detect EOF if I'm avoiding calling read() when there is no data available). Meanwhile I am reopening this issue.