DEV Community

Soumyajit Deb
Soumyajit Deb

Posted on

Unlocking some features of bash terminal

Well, most of us are familiar with bash terminal one way or another.Terminal is the most commonly used tool by developers and in general, for every person who is trying to execute a code on a computer.
Recently, while working on a project, I have learned a lot about some features of the bash terminal which are usually hidden and can be unlocked by doing some low level programming. Some of this features are pretty cool and can be helpful in many situations.These features of bash terminal are by default switched off.

Now without further delay, let's unlock those features!

1. ECHO

The Echo feature causes each key you type to be printed on the terminal, so you can see what you are typing. This can be turned off by changing some flags which control various attributes of the terminal. This can be done by doing some low level programming in C.

#include <termios.h>
#include <unistd.h>

void enableRawMode() {
  struct termios raw;
  tcgetattr(STDIN_FILENO, &raw);
  raw.c_lflag &= ~(ECHO);
  tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}

int main() {
  enableRawMode();
  char c;
  while (read(STDIN_FILENO, &c, 1) == 1 && c != 'q');
  return 0;
}

struct termios, tcgetattr(), tcsetattr(), ECHO, and TCSAFLUSH all come from termios.h.
After you execute this program, anything you type will not be printed on the terminal. You may be familiar with such feature of the terminal if you ever had to type a password at the terminal.
In the above program, we have used the termios header file, which contains functions which can change the attributes of the terminal.

struct termios is pre-defined structure which contain the terminal flags as the fields.

tcgetattr() helps to read the current attributes of the terminal and write them to the struct termios.

raw.c_lflag is the flag, which contains the bit, which controls the echo feature of the terminal.
ECHO is a bitflag, defined as 00000000000000000000000000001000 in binary. We use the bitwise-NOT operator (~) on this value to get 11111111111111111111111111110111. We then bitwise-AND this value with the flags field, which forces the fourth bit in the flags field to become 0, and causes every other bit to retain its current value. Flipping bits like this is common in C.

Terminal attributes can be read into a termios struct by tcgetattr(). After modifying them, you can then apply them to the terminal using tcsetattr(). The TCSAFLUSH argument specifies when to apply the change: in this case, it waits for all pending output to be written to the terminal, and also discards any input that hasn’t been read.

After the program quits, depending on your shell, you may find your terminal is still not echoing what you type. Don’t worry, it will still listen to what you type. Just press Ctrl-C to start a fresh line of input to your shell, and type in reset and press Enter . This resets your terminal back to normal in most cases.

The above program will quit as soon as you type q .

Bash terminal has primarily two modes, one is canonical mode and other one is raw mode. Now, bash terminal is by default in canonical mode. In canonical mode, the input in the terminal is taken line by line rather than byte by byte. Although line by line mode of input is helpful as in this case, we can backspace if some typo has occurred but sometimes this feature is not needed and byte by byte mode of input is of much help.Byte by byte mode of input is provided in raw mode if the terminal.

Similarly, we can change the mode of our terminal from canonical to raw mode by doing some low level C programming and changing some flags.

Canonical to Raw mode

There is an ICANON flag that allows us to turn off canonical mode. This means, now the terminal will be reading input byte by byte rather than line by line.

#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
struct termios orig_termios;

void enableRawMode() {
  tcgetattr(STDIN_FILENO, &orig_termios);
  struct termios raw = orig_termios;
  raw.c_lflag &= ~(ECHO | ICANON);
  tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}

 int main() {
  enableRawMode();
  char c;
  while (read(STDIN_FILENO, &c, 1) == 1 && c != 'q')
{
   if (iscntrl(c)) {
       printf("%d\n", c);
     } else {
      printf("%d ("%c")\n",c,c);
      }
}

  return 0;
}

You just have to BITWISE-OR(|) ICANON with ECHO in the above program and it will turn of the canonical mode and the terminal will be in raw mode.

The program will quit as soon as you press q .

To get a better idea of the raw mode, the program prints the key presses as soon as they are typed unlike canonical mode, where they were printed after a line is given as input and enter is pressed.

Top comments (0)