echo
writes its output to its stdout. That's its file descriptor 1.
With echo -e '\a'
, depending on the echo
implementation, that will either write a BEL character (0x7 byte value in ASCII) followed by LF (aka newline) or -e \a
followed by LF or -e
followed by BEL and LF.
To write a BEL character only, you'd rather write printf '\a'
.
That doesn't make much difference to the core of this question anyway. printf
, like echo
will write what it has to write to its stdout.
If you enter that command at the prompt of an interactive shell without redirection, stdout will be inherited from the shell. If the shell was started by a terminal emulator like xterm
or screen
, the file descriptor 1 will have been opened (by xterm
) on a /dev/pt<something>
device file (see lsof -ad1 -p "$$"
or readlink -f /proc/self/fd/1
on Linux). That will be the slave side of pseudo-terminal pair.
The only thing important to know about it here is that it's some sort of communication channel. A bit like a pipe except that it has a few more bells and whistles that help with user interaction.
So when printf
writes the BEL to that device file, what happens is that it's transmitted to something at the other end. In the xterm
case, that's the terminal emulator itself. The BEL character is a control character that make terminal and terminal emulators alert the user in some way (\a
is for alert). That can be an audible beep, chime or a visual flashing of the screen or both. xterm
will typically use the XBell()
X11 API call for that or flash its window if it's been configured to use a visual bell. screen
itself would simply forward the BEL to the host terminal(s) it is connected to and where that screen window is active or issue a terminal flash control sequence or "Wuff, Wuff!!" (sic) message depending on how it was configured (see info screen vbell
).
If you login on a PC running Linux outside of the graphic session, fd 1 will have been opened (by getty
) to a /dev/tty<1-...>
device. Here, it's the kernel that implements a terminal emulator and uses the monitor for output and keyboard(s) for input. Same principal, when printf
writes that BEL there, the kernel makes the PC speaker beep.
When you run that command at the prompt of an interactive shell over ssh
, fd 1 will also be a pseudo-terminal device (/dev/pt<something>
), this time started by the ssh server which started the login shell of the remote user on the remote system. At the other end of the pseudo-terminal pair is the ssh server. When receiving that BEL (or anything else for that matters), the ssh server sends that across the encrypted connection to the ssh client, and the ssh client writes it to its stdout, which will eventually make it to the terminal window you're sitting at.
In
printf '\a' > /dev/console
The shell opens the /dev/console
file on the file descriptor 1 (stdout) before running printf
.
Now /dev/console
, at least on Linux, is the tty device file that is meant to receive system messages. /dev/console
typically redirects to another tty device. On PC, by default, that's /dev/tty0
which points to the currently active virtual terminal, but that can be changed at boot time using the console=/dev/anything
kernel parameter (for instance console=/dev/ttyS0
to make it the first serial device), and it can even be changed (for the output part) later on, using the TIOCCONS
ioctl()
(see xterm -C
).
In any case, that will be a terminal that is typically attached to the machine itself. So outputting a BEL there is meant to alert the administrator of that machine as it's using the channel used to send system messages to the user.
To write a message to all logged in users, you can also use the wall
application, or the write
application to just one user (one terminal device), provided those users have not disabled those notifications (with mesg n
)