Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preexec runs before accepting the command line when using readline shell command bindings. #100

Open
curusarn opened this issue Oct 9, 2019 · 8 comments

Comments

@curusarn
Copy link

curusarn commented Oct 9, 2019

Readline allows us to bind arbitrary shell commands to key sequences using bind -x. Using these shell commands results in preexec() being executed before accepting the command line instead of after. Plus preexec() is executed with the same argument twice effectively skipping the next accepted command-line.

Example

  • Define preexec() and precmd()
(ins)[simon@simon-pc ~]$ preexec() { echo "just typed $1"; }
(ins)[simon@simon-pc ~]$ precmd() { echo "printing the prompt"; }
printing the prompt
  • Run some commands to see normal behavior
(ins)[simon@simon-pc ~]$ echo first
just typed echo first
first
printing the prompt
(ins)[simon@simon-pc ~]$ echo second
just typed echo second
second
printing the prompt
  • Bind a simple shell command to Control+X
(ins)[simon@simon-pc ~]$ bind -x '"\C-x": READLINE_LINE="echo typed by readline"'
just typed bind -x '"\C-x": READLINE_LINE="echo typed by readline"'
printing the prompt
  • Run normal command
(ins)[simon@simon-pc ~]$ echo third
just typed echo third
third
printing the prompt
  • Now press Control+X
    We can see that preexec() was run before we accepted the command line. We can also notice that preexec() run with the same argument as moments before.
just typed echo third
(ins)[simon@simon-pc ~]$ echo typed by readline
  • Now press Enter to accept the command typed by readline
    We can see that preexec() wasn't executed this time effectively skipping the command-line typed by readline.
typed by readline
printing the prompt
(ins)[simon@simon-pc ~]$ 
@curusarn
Copy link
Author

This issue is very similar to this one: #27

@dimo414
Copy link
Collaborator

dimo414 commented Mar 15, 2020

Do you have any thoughts for how bash-preexec could better handle this situation? I don't think a consensus was reached in #27.

@curusarn
Copy link
Author

My immediate thought was to use some of the variables that are set when readline widgets are executed (READLINE_LINE, READLINE_POINT). The problem is that these are not set when the trap is triggered.

I have read the bash manual to look for other suitable variables but I couldn't find any.

I needed to solve this in my project. (https://github.com/curusarn/resh)
I did work around this by re-enabling bash-preexec in my own custom readline widgets/functions.
Setting __bp_preexec_interactive_mode="on" re-enables the hook so it runs again. I don't do anything disruptive in my hooked functions so I can safely rerun them like this. I discard the bogus data I get from all the invocations before the last proper one. (https://github.com/curusarn/resh/blob/master/scripts/widgets.sh#L10)

Needless to say, this is nor very safe nor usable in the general case. It breaks if someone uses their own custom readline functions/widgets (luckily this is not common). Not all projects can get away with invoking the hooks repeatedly.

I have just messaged the bug-bash@gnu.org mailing list to ask them if there is a way to determine why the DEBUG trap was triggered. If it was invoked because of "real" interactive command or because of custom readline function/widget.

@curusarn
Copy link
Author

This is a reply I got from Chet Ramey:

On 3/15/20 7:41 AM, Šimon Let wrote:

Hi All,

I'm using PROMPT_COMMAND and DEBUG trap to emulate "PRE" and "POST" hooks
in bash. I have run into the issue where the DEBUG trap gets triggered when
any custom readline widget/function is executed. I would like to
programmatically determine if the DEBUG trap was triggered for a "real"
interactive command or if it was triggered for a custom readline widget.

Since the DEBUG trap happens before the command executes, it's not a real
`post-command' hook.

I tried to use READLINE_LINE and READLINE_POINT variables but these are not
set during the DEBUG trap.

They're not set when the the DEBUG trap runs before, say, a shell
function you've bound to a key sequence using `bind -x' is executed, but
they're available to commands called from within that shell function.

Is there another way that can be used to determine why the DEBUG trap was
triggered?

No.

PS: I'm wondering what is your opinion on providing PRE and POST functions
natively in bash?

I'd have to see a compelling reason to implement them.

Chet

@curusarn
Copy link
Author

The most important part is that there is no way to tell why was the DEBUG trap triggered.

It seems that there are two options:

  1. come up with some ridiculous hack (maybe somehow use both PS0 and DEBUG trap) - unlikely
  2. try to persuade maintainers of bash to make it possible to tell or even to support PRE POST hooks natively

@dimo414
Copy link
Collaborator

dimo414 commented Mar 16, 2020

It's worth remembering that bash-preexec is attempting to implement support for pre/post on top of a shell that doesn't provide this functionality (as Chet said). There will likely always be gaps in functionality because of this Bash design decision, and if Bash ever provided proper hooks this project would no longer be needed[1].

Certainly if you can identify a reasonable combination of hooks that get what you need without regressing other user experiences it might be possible to improve bash-preexec, but you'd likely be in the best position to drive that.


[1]: But even if a new Bash version implemented hooks people will be running older Bash versions for the foreseeable future, so making changes to Bash itself won't help most users for a fairly long time.

@Rogach
Copy link

Rogach commented Mar 20, 2024

I think this issue might be solved by #152 - the updated version works for me, keybindings set up with bind do not result in preexec hooks running.

@akinomyoga
Copy link
Contributor

I think you are right. The problem reported here should be fixed by #152.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants