Unlocking some features of bash terminal
Tags: bash, c, ubuntu, tutorial
Published: 2019-12-10 05:16:55

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.

```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 <kbd> Ctrl-C </kbd> to start a fresh line of input to your shell, and type in *reset* and press <kbd> Enter </kbd>. This resets your terminal back to normal in most cases.

**The above program will quit as soon as you type  <kbd> q </kbd>.**

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.

```c
#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 <kbd> q </kbd>.* 

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 <kbd>enter</kbd> is pressed.