Computer terminals have traditionally had an actual bell that would ring when a certain control character (the bell character, typically control-g or \a in an C escape sequence) would come in the input stream.

That feature actually predates computers altogether, and was present in Baudot code, "an early character encoding for telegraphy invented by Émile Baudot in the 1870s", itself superseding Morse code.

Modern terminal emulators have, of course, kept that feature: if you run this command in a terminal right now:

printf '\a'

... you may hear some annoying beep. Or not. It actually depends on a lot of factors, including which terminal emulator you're using, how it's configured, whether you have headphones on, or speakers connected, or, if you're really old school, a PC speaker, even.

Typically, I have this theory that it does the exact opposite of what you want, regardless of whether you have configured it or not. That is, if you want it to make noises, it won't, and if you want it to stay silent, it will make brutal, annoying noises in moments you would the least expect. I suspect this is a law in computer science, but I'm too lazy to come up with a formal definition.

Yet something can be done with this.

Making the bell useful and silent

Many terminal emulators have this feature where they can silence the bell somehow. It can be turned into a "visual bell" which basically flashes the screen when a bell arrives. Or that can also be disabled and the bell is just completely ignored.

What I did instead is turn the bell into a "urgency hint" (part of the ICCCM standard. In xterm, this is done with this X resource entry (typically in ~/.Xresources):

XTerm*bellIsUrgent:  true
XTerm*visualBell: false

Interestingly, this doesn't clearly say "bell is muted", but it's effectively what it does. Or maybe it works because I have muted "System Sounds" in Pulseaudio. Who knows. I do have this in my startup scripts though:

xset b off

... which, according to the xset(1) manpage, means

If the dash or 'off' are given, the bell will be turned off.

Interestingly, you have the option of setting the bell "volume", "pitch, in hertz, and [...] duration in milliseconds. Note that not all hardware can vary the bell characteristics." In any case, I think that's the magic trick to turn the darn thing off.

Now this should send urgency hints to your window manager:

sleep 3 ; printf '\a'

Try it: run the command, switch to another desktop, then wait 3 seconds. You should see the previous desktop show up in red or something.

In the i3 window manager I am currently using, this is the default, although I did set the colors (client.urgent and urgent_workspace in bar.colors).

Other window managers or desktop environments may require different configurations.

Sending a bell...

Now that, on itself, will only be useful when something sets a bell. One place I had found a trick like this, long ago, is this post (dead link, archived) which has various instructions for different tools. I'll recopy some of them here since the original site is dead, but credit goes to the Netbuz blog.

(Note that the blog post also features an Awesome WM configuration for urgency hints.)

Mutt

set beep=yes
set beep_new=yes

Irssi

/set beep_when_window_active ON
/set beep_when_away ON
/set beep_msg_level MSGS DCC DCCMSGS HILIGHT

It was also recommending this setting, but it appears to be deprecated and gives a warning in modern irssi versions:

/set bell_beeps ON

GNU Screen

This is an important piece of the puzzle, because by default, terminal multiplexers have their own opinion of what to do with the bell as well:

# disabled: we want to propagate bell to clients, which should handle
# it in their own terminal settings. this `vbell off` is also the
# upstream and tmux's default
#
# see also: http://netbuz.org/blog/2011/11/x-bells-and-urgency-hints/
vbell off
# propagate bell from other windows up to the terminal emulator as well
bell_msg 'Bell in window %n^G'

The bell_msg bit is an extra from me: it uses the bell message that pops up when screen detects a bell in another window to resend the bell control character up to the running terminal.

This makes it so a bell in any multiplexed window will also propagate to the parent terminal, which is not the default.

Tmux

Untested, but that is apparently how you do it:

# listen to alerts from all windows
set -g bell-action any
# notice bell in windows
set -g monitor-bell on
# only propagate bell, don't warn user, as it hangs tmux for a second
set -g visual-bell off
# send bell *and* notify when activity (if monitor-activity)
set -g visual-activity both

Note that this config goes beyond what we have in GNU screen in that inactivity or activity will trigger a bell as well. This might be useful for cases where you don't have the prompt hack (below) but it could also very well be very noisy. It will only generate noise when monitor-activity is enabled though.

bash and shell prompts

Now the icing on cake is to actually send the bell when a command completes. This is what I use this for the most, actually.

I was previously using undistract-me for this, actually. That was nice: it would send me a nice desktop notification when a command was running more than a certain amount of time, and if the window was unfocused. But configuring this was a nightmare: because it uses a complex PROMPT_COMMAND in bash, it would conflict with my (already existing and way too) complex bash prompt, and lead to odd behaviors. It would also not work for remote commands, of course, as it wouldn't have access to my local D-BUS to send notifications (thankfully!).

So instead, what I do now is systematically print a bell whenever a command terminates, in all my shells. I have this in my /root/.bashrc on all my servers, deployed in Puppet:

PROMPT_COMMAND='printf "\a"'

Or you can just put it directly in the shell prompt, with something like:

PS1='\[\a\]'"$PS1"

(I have the equivalent in my own .bashrc, although that thing is much more complex, featuring multi-command pipeline exit status, colors, terminal title setting, and more, which should probably warrant its own blog post.)

This sounds a little bonkers and really noisy, but remember that I turned off the audible bell. And urgency hints are going to show up only if the window is unfocused. So it's actually really nice and not really distracting.

Or, to reuse the undistract-me concept: it allows me to not lose focus too much when I'm waiting for a long process to complete.

That idea actually came from ahf, so kudos to him on that nice hack.

Caveats

That is not setup on all the machines I administer for work, that said. I'm afraid that would be too disruptive for people who do not have that configuration. This implies that I don't get notifications for commands that run for a long time on remote servers, most of the time. That said, I could simply run a command with a trailing printf '\a' to get a notification.

This might not work in Wayland, your window manager, your desktop environment, your Linux console, or your telegraphy session.

avoiding the beep...

Not loading the pc speaker module is the only reliable way I have found of turning off the beeps...

echo "blacklist pcspkr" > /etc/modprobe.d/pcspkr-blacklist.conf

Comment by Joseph
Remarks

I'm actually using this technique for years (at least five). You don't even need a PROMPT_COMMAND. You can directly embed the bell in PS1. However, you should tell your shell that it is an escape sequence (and thus not adding to prompt length): \[\a\]

I also confirm that this works well both in xterm + awesome on Xorg and foot + sway on wayland.

Comment by Helmut Grohne
shell escapes

You can directly embed the bell in PS1. However, you should tell your shell that it is an escape sequence (and thus not adding to prompt length): \[\a\]

Ah! That's one bit I was missing... without that, readline gets pretty confused. Thanks! I'll update the post...

Comment by anarcat
Comments on this page are closed.
Created . Edited .