2

The terminal bell rings in several scenarios. To name a few:

  1. when you attempt to delete when at the beginning of a prompt
  2. when you attempt to tab complete with no valid options
  3. in vim, when you attempt to move the cursor when i cannot move (i.e. move down while on the last line)

And there's plenty others. What I want to do is make is to the only time the bell will ring is when I deliberately make it ring, such as with echo -e "\a".

I've added set bell-style none to my .inputrc, but it still rings in vim, and if I start tmux, I get the first 2 bells above as well. I it possible to tell bash never to ring the bell unless I deliberately tell it to?

ewok
  • 4,641

1 Answers1

0

Analysis

echo -e "\a" prints the BEL character, 0x07 in ASCII (and a trailing newline which is irrelevant for us). Your terminal (terminal emulator), when it gets this exact character, instead of showing you some glyph (like e.g. it shows a upon receiving 0x61) causes an audible, visible or whatever notification.

The path may be longer, for example:

  1. Your echo -e "\a" is run in a shell inside a tmux pane. The terminal emulator is your tmux server. It may react to the BEL character in some way and/or pass it further.

  2. If the tmux server passes the character further then the character will get to your tmux client which will just print it like echo -ne "\a" would.

  3. The terminal under which the tmux client runs may react to the BEL character. A virtual console may trigger a beep. A terminal emulator may play a sound, flash its window or ask your desktop environment to show a popup notification.

The most important thing is neither the tmux server nor the tmux client nor the terminal emulator nor the desktop environment can know if this BEL character came from echo or from Bash or Vim or what.

There is this concept of the foreground process group. In the above scenario the terminal emulator knows the foreground process is the tmux client. Similarly the tmux server gets informed (by the interactive Bash in the pane) what process group is in the foreground at the moment. The tmux server is in a relatively good position for what you want to do, it could take an educated guess that BEL came from the process group leader; but:

  • There may be more processes in the foreground process group and each one could have generated the BEL.
  • When the tmux server starts analyzing the situation, the process that had generated the BEL may have already terminated, the foreground process group may have changed. In other words it may be too late for any educated guess.
  • The BEL may have been generated by a process in the background.
  • The BEL may have been generated by a process started in another pane or wherever.
  • If the "process" is echo -e "\a" run in an interactive Bash, then it's actually a shell builtin and the process that generates BEL is Bash; the same Bash that generates BEL when you attempt to delete when at the beginning of a prompt. So even if the tmux server could reliably tell what process had generated BEL, this wouldn't be enough to distinguish what you want to distinguish.

Direct answer to the explicit question

Is it possible to tell bash never to ring the bell unless I deliberately tell it to?

Yes, it's set bell-style none for Readline Bash uses, you have already discovered it. Some bells you want to block have nothing to do with Bash though. Remember the shell does not act as a relay between programs and the terminal. If a program prints a BEL character to a tty then it's just like that: the program prints to the tty directly, the shell and its settings don't affect this.


Possible solutions to the actual problem

(The list below is not meant to be exhaustive.)

  • Configure each program (like Vim) or library (like Readline) separately. For some programs this may be impossible.

  • Disrupt the path BEL takes. Then, whenever you want to deliberately make it ring, take a "shortcut" and circumvent the disruption. E.g. if you configure your terminal emulator to ignore BELs completely, the shortcut would be to manually do what the terminal emulator would otherwise do: play a sound or trigger a notification. Another example is below.


Example

This example is for tmux. Run the commands in a shell inside a tmux pane.

To disrupt BELs at the tmux server:

tmux set monitor-bell off

To take a shortcut and print a BEL character to a tty of the tmux client:

printf '\a' > "$(tmux display-message -p '#{client_tty}')"