Demystifying Keyboard Input And Text Output In Unix Systems

Understanding Standard Input and Output

The standard input (stdin), standard output (stdout), and standard error (stderr) are three data streams that are associated with every Unix process. The stdin stream provides input data to a process, stdout streams output data from a process, and stderr streams error data from a process.

The stdin stream corresponds to the keyboard input in an interactive Unix shell. By default, stdout and stderr both correspond to the text printed to the terminal. These default associations can be changed through a technique called redirection.

Redirection allows you to capture the output of a process to a file rather than printing it to the terminal. It can also take input for a process from a file rather than the keyboard. Redirection makes use of the ‘<' , '>‘ and ‘|’ operators.

‘command > file’ will redirect the stdout stream to ‘file’, appending any output to the end of the file. ‘command < file' will redirect the stdin stream to come from 'file' rather than the keyboard. The '|' operator pipes the stdout stream of one process into the stdin stream of another process, allowing you to chain commands.

As an example, ‘ls -l > output.txt’ will execute the ‘ls -l’ command and redirect its output to be appended to the ‘output.txt’ file. ‘wc -l < output.txt' will print the line count of 'output.txt', taking the contents of that file as its stdin input rather than the keyboard.

Reading Keyboard Input in Unix

Keyboard input in a Unix system comes from the user’s terminal device. This is often emulated in a terminal program like xterm, gnome-terminal, etc. There are two types of input supported – buffered input and unbuffered input.

Buffered input allows the user to edit entire lines before they are passed to the program. Features like backspace editing and history search rely on buffering. Unbuffered input passes each key press directly to the program without any editing, and is rarely used today outside of specialized applications.

A program can read keyboard input by simply reading from the stdin stream one line at a time. In C, functions like fgets() and getline() are used. In shell scripts, the ‘read’ builtin allows capturing stdin input into a variable.

As an example, this C code uses fgets() to read a line into a buffer:

char input[100];
fgets(input, 100, stdin);

Similarly, this bash snippet uses ‘read’ capture stdout into the REPLY variable:

read -p "Enter input: "
echo "You entered: $REPLY" 

Printing Text to Terminal

The easiest way to print text to the terminal is write data to the stdout stream. In C, the printf() function allows flexible text output with formatting strings embedded with the text.

format strings start with ‘%’ and indicate how to format the next argument passed to printf(). For example ‘%d’ formats an integer, ‘%f’ formats a float value. Escape sequences embed special codes within strings – for example ‘\n’ will print a newline.

Some useful escape sequences when printing to the terminal are:\n
– \033[0;31m – Starts red text coloring\n
– \033[0m – Resets text formatting back to default terminal colors\n
– \033[2K – Erases the entire current line\n

By combing printf() and these escape sequences, C programs can print colored, formatted output:

 
printf("\033[0;31mError:\033[0m Invalid input");

Bash provides echo as the primary command for printing text, but it does not support the advanced escape sequences that C provides. So bash scripts tend to use more basic terminal output.

Controlling the Terminal

A Unix terminal operates in either canonical or non-canonical input mode. The default is canonical mode, which enables line editing features like backspace and history search. Disabling canonical mode switches the terminal to unbuffered character-at-a-time input.

Terminals also support echo, which prints typed characters back to the screen. Programs may disable echo in order to implement invisible password entry for example.

In C, the termios library can get and set various terminal attributes to control modes like this. The tty program can also inspect and modify terminal settings.

As an example, this termios code disables canonical mode for password entry:

#include <termios.h>

int main() {
   struct termios t_old, t_new;

   tcgetattr(STDIN_FILENO, &t_old);
   t_new = t_old;
   t_new.c_lflag &= ~ICANON;
   tcsetattr(STDIN_FILENO, TCSANOW, &t_new);
   
   // read password here   
   
   tcsetattr(STDIN_FILENO, TCSANOW, &t_old); 
}

From a bash script, running ‘stty -icanon’ before a ‘read’ command can similarly disable canonical mode temporarily.

Interacting with Users

Following some basic guidelines helps ensure keyboard input and text output in Unix is intuitive for end users:

  • Use clear, descriptive prompt messages when requesting input
  • Preface error messages clearly with the text ‘Error’ or similar
  • Avoid very long output lines that require horizontal scrolling
  • Allow usage of arrow keys and edit history for input read from users
  • Echo password/sensitive input back as asterisks rather than cleartext

The bash read builtin includes many flexible options to implement user-friendly input functionality:

read -p "Enter password: " -s mypass
echo "You entered $mypass"

Here -p shows a prompt message, and -s hides the input as asterisks. Input is saved into the $mypass variable.

By using read judiciously and following output guidelines, shell scripts can have natural feeling command line interfaces.

Leave a Reply

Your email address will not be published. Required fields are marked *