# Productivity Tips: Understanding and Make Use of Unix Standard Streams

Unix standard streams, a basic unix process that always tied with (`stdin`, `stdout`, and `stderr`). Probably you may use it in your software without even knowing it. Let's understand deeper and how you can make use of the standard streams and apply into your workflow to gain the development productivity. This article won't explain and cover the standard streams in details, however **the main aim of this article would be focused on using the three standard streams and the basic unix Standard I/O (Input / Output) operator like pipeline and redirection.**

## Standard Streams

Starting with the Standard Streams, it is the most basic fundamentals in the Unix and Unix-Like Operating system like Linux, BSD and Mac OS. By default, it consists of three main file process such as.

1. `stdin` that means standard input,
    
2. `stdout` that means standard output, and
    
3. `stderr` that means standard error.
    

Every application must use of those three standard I/O above to process input and output. As we know, every application have many processes. In each process, they use three standard file descriptors in the unix-like operating system, `stdin` as the input, `stdout` as their basic output, and `stderr` as the error output. To visualize what are those our computer, it can be demonstrated using the picture below.

### File Descriptor in standard streams

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1710342040967/0515e411-3988-41aa-b219-739cf9877297.png align="center")

In the picture above, there is a process will interact with a three numbers, which 0 that belong to `stdin`, 1 to `stdout`, and 2 to `stderr`. The number represented is the file descriptor opened in each process. Since unix system follow the philosophy of "everything as a file", then the standard streams would be accessible from `/dev/stdin` as the input stream file, `/dev/stdout` as the standard output stream, and `/dev/stderr` as the standard error output stream. Digging deeper in the golang standard library, the `Stdin`, `Stdout`, and `Stderr` files are predefined with path explained before.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711188117045/5e13a5b2-b880-4196-a878-5190d1d6e7be.png align="center")

Let's write a simple demo program using go that use `stdin`, `stdout`, and `stderr`.

```go
package main

import (
	"fmt"
	"io"
	"os"
	"strings"
)

func main() {
	stdin, err := io.ReadAll(os.Stdin)

	if err != nil {
		panic(err)
	}
	str := string(stdin)

	lowercased := strings.ToLower(str)

	fmt.Fprintf(os.Stdout, "Hi %s", strings.ReplaceAll(lowercased, "\n", ", "), )
	fmt.Fprintf(os.Stdout, "\n")
	fmt.Fprintf(os.Stderr, "There is no error, this is just an example\n")
}
```

The simple go code above would do the following actions:

1. Read all input given in the standard input.
    
2. Convert the input string to be all lowercase and concatenate them if the inputs is more than one line.
    
3. Print the lowercased string into standard output.
    
4. Print something into standard error just for example.
    

While running those program, we will get the input from the `os.Stdin` (in golang, it is the standard input stream file. The input then will be buffered into the `stdin` variable that turned into lowercased string later.

To print an output to the terminal, we prefer using the `fmt.Fprintf()` function instead of `fmt.Println()` because under the hood, the `fmt.Println` method also write bytes to the `os.Stdout` (golang standard output file). It is the same though, it just to simplify our learning points about the unix basic standard streams. To print out to the standard error output, we also use `fmt.Fprintf()` function to print the error message to `os.Stderr` that will be explained later in this post.

> In this post, to make sure that you will be learning something, the post will prefer using screenshot only for the command used in the example. This is intended to aim you to try and type the command by yourself.

## Standard Input (stdin)

First thing first, let's build the program above using the following command.

```bash
go build main.go
```

The output binary file should be named `main` in the same directory. Before execution, we will explain several standard input operators such as pipe operator that can be denoted with the `|` and the `<` less than operator.

### Input Redirection &lt; Operator

Input redirection means that we can replace the input using the files or custom input we decided to use. In this example we use a separated file named `names.txt` that contains three names in the file.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711190175032/cd0bd38b-8e42-414d-8e52-1cbee997c346.png align="center")

To redirect the standard input, we can use `<` (less than) operator. The convention of its full command would be the `binary < input` . It can be shown in the example below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711190269290/d4cbb25d-a778-4cdb-b260-b1465b2cae84.png align="center")

The picture above show that we can redirect the input using the `<` operator to replace the input data streams from `/dev/stdin` to `names.txt`.

### Pipe | Operator

Pipe will be useful to combine two commands, it will **take the output of the first command as the inputs of the second command**. Let's take the example of the pipe operator usage in the terminal history below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711189604105/e2f6f3a9-d192-4538-8c26-ccd6f78e4e9f.png align="center")

The commands used in the picture above is `echo` that print something to the standard output, and the `main` command (the previous simple application) will take the echo command as the input of the program.

> Hi **<mark>hai</mark>**,
> 
> There is no error, this is just an example

In the first run, the output "Hai" will be used in the `main` command as the standard input. Our `main` command do the lowercasing of the "Hai" input and printed out as "hai" with the following additional output in the terminal.

In the second run, the output from echo command is "Rendy" that will be lowercased by executing the `main` command as it gave the output below.

> Hi **<mark>rendy,</mark>**
> 
> There is no error, this is just an example

Take another look with another command, `ls` to show our files in the current directory. Combining with pipe operator and `main` command gave us similar output.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711189992077/63fb0582-d104-431e-b940-a909fb8e8e12.png align="center")

The `ls` command giving output of the files inside the directory and piped with the `main` command. All of the files would nicely concatenated using comma.

## Standard Output (stdout)

Standard output has two operators such, that is the output redirection with replacing file and output redirection with append file. The replace operator use the `>` (greater than), and append operator use `>>` (double greater than) symbols.

### Redirect Output &gt; Operator

First example, we will use the standard unix command like `echo` to redirect the output into a file.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711272747972/a290056c-fdf7-4422-a1c5-1055e9f9a03d.png align="center")

In the example above, we can understand that the string "Hello" is written through the file named `hello.txt`. If we do the the same thing with a different string, the `hello.txt` file will be replaced with the new string. It can be shown by the example below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711272944131/bc37fbf8-d3ba-4121-bde9-11cb30f63f2b.png align="center")

As the example above, we don't intentionally delete the files but the old `hello.txt` file that contains "Hello" got replaced by a new string "Rendy". If we don't want to replace the string, then we should use the append output redirection operator `>>` .

### Append Output &gt;&gt; Operator

In the second attempt, we will using the same file hello.txt and write another string to the this file but using the append `>>` operator.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711273280711/d406fa87-5d43-462c-836f-6213e7c695dc.png align="center")

In the example above, we can see that the `>>` operator did not change the file contents of the `hello.txt`. Instead it will append the "George" string below the existing file contents.

The standard output and standard input redirection operator can be used together with the `main` program we wrote before.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711273604988/1727120a-eb4b-42a4-80ed-4c902946ce03.png align="center")

With the command above, you can see that the `Hi rendy` string is not printed in the terminal, instead it written in the `main.log` file. Hence the example error line <mark>"There is no error, this is just an example"</mark> that is **printed in the standard error would still shown in the terminal output because we only redirect the standard output.**

## Standard Error (stderr)

Basically, redirecting the standard error would still the same intuition as the standard output. Remember that the standard error using `2` as the file descriptor number in [this picture](https://rendyananta.my.id/productivity-tips-understanding-and-make-use-of-unix-standard-streams#heading-file-descriptor-in-standard-streams)? We only need to redirect them using 2 prefix in each operator. For instance, to redirect the standard error we can use `2>`, and to redirect append output of a standard error we can use `2>>`. Let's try that using the `main` command.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711274364216/d41bcfd3-c2ff-4ec5-a53f-a2cdd55a5b30.png align="center")

The picture above shown that we already successfully redirect the standard error to the `error.log` file. While using the append operator, we will got the similar result as the picture below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711274573713/adbe1acf-f718-49ab-a100-9abe76b1f18f.png align="center")

That is the basic usage of the standard input, standard output, and standard error operator in bash system.

# Advanced Use Cases

After understanding its function and available operators in the standard streams, there is a bunch another use case combination of its that may help improving our productivity. Utilizing the `main` program we wrote before, we can redirect the standard output to a file, and the standard error to another file like the picture below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711275147823/db0943c6-e7bd-47c8-8209-5c9625fbf1a9.png align="center")

In some cases, there is needed a bigger input, usually from a file. It is possible by leveraging the `<` operator as the example below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711275266255/06b68381-f6bb-4107-84d2-9faa8876523d.png align="center")

There another use case that need to combine all of the output of standard error and standard output in a one file.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711275340992/61a43b2d-90ee-436a-be1e-28cc5370cd46.png align="center")

Usually we have a bunch of files in the same directory (usually logs). To querying some string, we can use the `cat` command to list all of the files that match the pattern, and find the relevant information using `grep` command.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1711275562042/bdce1b67-1ab1-4325-ab43-c4b6159ef049.png align="center")

That's all. Understanding the basic standard input and output streams of unix system is worth it. We can improve the productivity because we don't need to open the IDE that may heavy, or even impossible in the production server.
