hanslub42 / rlwrap

A readline wrapper
GNU General Public License v2.0
2.53k stars 149 forks source link

redirected rlwrap does not leave terminal in original state #145

Closed haji-ali closed 1 year ago

haji-ali commented 2 years ago

If I try this example in bash on rlwrap 0.43

reply=$(rlwrap -S 'Do you want to continue? ' -f <(echo "Yes No Maybe") -o cat)

but then abort (with Ctrl-C) instead of inputting anything, my bash prompt gets broken (I cannot enter any input). Any subsequent calls to rlwrap also put me in an infinite loop.

Is this expected? How do I fix it?

My bash is

GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
hanslub42 commented 2 years ago

I cannot reproduce this, on my machine your example works without any problems. What happens if you enter the following command in bash:

 rlwrap -S 'Do you want to continue? ' -f <(echo "Yes No Maybe") -o cat

... and then press Ctrl-C?

haji-ali commented 2 years ago

This works as expected. It's only when I assign to a variable that I observe those problems. Strangely, I also just tried on a different machine with an older bash and could not reproduce it.

I am not 100% sure how to troubleshoot this issue, please let me know if you have any ideas. Meanwhile, I will try to install an older bash and report back.

UPDATE: Just tried an older shell (4.2.46(2)-release-(x86_64-redhat-linux-gnu)), on my machine and I am not observing the problematic behavior. So the problem must be a compatibility one with 5.0.17(1)-release (x86_64-pc-linux-gnu). This is the one that ships with Ubuntu.

haji-ali commented 2 years ago

Just compiled bash from here, using

curl https://ftp.gnu.org/gnu/bash/bash-5.0.tar.gz | tar zxf -
cd bash-5.0
./configure && make && ./bash

Then tried the command above

bash-5.0$ reply=$(rlwrap -S 'Do you want to continue? ' -f <(echo "Yes No Maybe") -o cat)

and hit Ctrl-C immediately and was able to reproduce the problem.

@hanslub42, can you reproduce the problem this way?

PS: I also tried bash 5.1 and could not reproduce the problem there.

PPS: The problem appears when running rlwrap version 0.43 which is the one bundled with my distros and form a compiled rlwrap from the source on this repo.

UPDATE: Before running rlwrap, I have these stty options (among others)

lnext = ^V; discard = ^O; 
icrnl icanon echo

but after running rlwrap and pressing Ctrl+C, these are changed to:

lnext = <undef>; discard = <undef>;
-icrnl -icanon -echo 
hanslub42 commented 2 years ago

The problem already appears with a simple:

reply=$(rlwrap cat)

rlwrap remembers the terminal settings at startup and always restores them immediately before exiting (even after a SIGINT). I can verify that this happens in the above case as well, and that those terminal settings have the ECHO bit set (as expected). That means that is must be bash that clears the ECHO bit after rlwraps death.

ALl this makes me doubt that there is much I can do to prevent your problem from occurring. The fact that it doesn't happen with the newest bash only reinforces this doubt.

haji-ali commented 2 years ago

Yes, I also came to the same realization. I ended up trapping SIGINT in my script that calls rlwrap and restoring the stty settings which fixes the issue for my particular case on bash 5.0.

Since this bug seems more relevant to bash 5.0 than to rlwrap, I will close the issue. Thank you for checking.

hanslub42 commented 2 years ago

I suddenly realise that rlwrap should restore the terminal settings by manipulating the tty that is connected to stdin (currently it works on stdout). Usually, both are connected to the same tty, but not in cases where rlwraps output is redirected, as in the question above. Duh!

Reopening....

hanslub42 commented 1 year ago

I suddenly realise that rlwrap should restore the terminal settings by manipulating the tty that is connected to stdin (currently it works on stdout). Usually, both are connected to the same tty, but not in cases where rlwraps output is redirected, as in the question above. Duh!

This is not true, my mistake The manual states:

When stdout (or stderr) is not a terminal, rlwrap will re-open it to /dev/tty (the users terminal) after it has started command, so that command's output is redirected as expected, but keyboard input and rlwrap error messages are still visible

So even though rlwrap restores the terminal settings by manipulating stdout, this will always be connected to the users teminal

Morover, I can reproduce the problem with bash 5.0, but not with bash 5.1 anymore. Conclusion: this was not a rlwrap problem after all. Closing