loading...
Cover image for Stupid Short: Bash's |, >, >>, >, 2> Operators

Stupid Short: Bash's |, >, >>, >, 2> Operators

bananabrann profile image Lee ・4 min read

This is meant to be a stupid-short introductory and reference guide for quickly understanding these Bash operators: >, 1>, >>, 1>>, <, 2>>, 2>>. This is primarily done with one sentence and an example.

This guide assumes...

  1. ... you are using Bash terminal. (OS is not relevant)
  2. ... you are familiar with CLI usage and navigation.
  3. ... you are familiar with the concepts of Bash program arguments/flags/options.

Contents

Note: For this blog, we will assume we are only writing and reading files.


Mostly-Short Fundamentals

Admittedly, I never bothered to look up what the | > >> and < operators do in Linux until well into my programming career. If you've ever followed GitHub's instructions for adding an SSH key to your account, then you've already used are called Redirect Operators!

Fundamentals of Programs

A program has three input and output streams with their corresponding number. It has a standard input (STDIN)(0), standard output (STDOUT)(1), and standard error (STDERR)(2).

Chart of program I/O streams

Note: My beautiful picture is only showing convention. If you build your own program, you can effectively name streams whatever you'd like and stream to whatever output. You don't know that though. If you do, act like you don't and read on.

Example: Let's take the good ol' ls. When you ls with no error, the input is ./ (Bash assumes empty is current directory), the stdout is the list of directories you then see, and the stderr is nothing (Because there's no error to catch).

Programs stream both stdout and stderr; this is because it's not "stdout or stderr", it's "stdout and stderr". Running ls presentDir notPresentDir, you can see both stdout and stderr.

By default, stdout, stderr, and stdin are all in the terminal. With these redirection operators, we're simply redirecting those streams elsewhere.


Vocab

"program": This is what executables are called in terminal. Every time you cd or ls, you're running a program.
cat: Program that prints the contents of a given file.
wc -w: Program that outputs the count of words in a file.
pbc: My alias for xclip -selection clipboard. For Mac folks, this is the exact same thing as pbcopy.
pbp: My alias for pasting clipboard.


Stupid-Short List

⭐️ The redirect operators have three numbers correlating with the output: 0 = input, 1 = output, 2 = error. If no number is given, this defaults to 1.
⭐️ If the file does not exist, these operators create the file.

> Write stdout to given file.

Sends stdout to a given file, instead of printing in the terminal.

$ ls -1 > list.txt

$ cat list.txt
lubbock.txt
odessa.txt
baird.txt

>> Appends stdout to given file.

Adds stdout to file contents, not replacing file contents.

$ echo "Flamingo" >> favorite-birds.txt

$ cat favorite-birds.txt
Cardinal
Penguin
Flamingo

< Redirects file as stdin

Passes the contents of a file as the stdin.
Example: If we use wc -w book.txt, the program will output the word count and the filename of book.txt (ex: 2394 book.txt).
If we use wc -w < book.txt we are "passing in" the contents of book.txt as the input, therefore wc -w < book.txt would return only the number (2394), as if we typed the whole thing into terminal.

$ wc -w book.txt
2394 book.txt

$ wc -w < book.txt
2394

2>: Redirect stderr to given file.

If there is an error, redirect the stderr to a file instead of printing in terminal.

$ ls cuteDogPics 2> example.txt

$ cat example.txt
ls: cuteDogPics: No such file or directory

2>>: Appends stderr to given file.

Exactly like >> and >, except with stderr.

$ cp ~/Documents/Reports/June2019.xlsx ~/Desktop 2>> ~/error.log

$ cat ~/error.log
cp: /Users/bananabrann/Reports/January2019.xlsx: No such file or directory
cp: /Users/bananabrann/Reports/March2019.xlsx: No such file or directory
cp: /Users/bananabrann/Reports/June2019.xlsx: No such file or directory


|: Use the stdout as stdin for the next program.

Use the stdout of the program left of the | as stdin to the program to the right.

$ ls -1
buffalo-gap.txt
abilene.txt
clyde.txt
lubbock.txt

$ ls -1 | head -2
buffalo-gap.txt
abilene.txt

Able to be daisy-chained

Using the |, we can ultimately chain as many programs as we'd like to achieve the desired result.
In the picture below, we take the stdout of the grep program and send it as the stdin of head and its arguments. We then send that stdout to the stdin of tail, then finally redirect the stdout to guestlist.txt.

Alt text of image


Hope this helped someone, or sparked someone's interest to play around with these operators and research further on their own!

Happy Coding! 🍻

Discussion

pic
Editor guide
 

Here's one more I'm using sometimes:

$ call-foo > out_and_err.txt 2>&1

So here I'm redirecting STDERR to the address of STDOUT, which is a file called "out_and_err.txt".

 

I think that in recent bash and zsh, one can use

call-foo &> out_and_err.txt
 

This is my favourite "shut up, I don't want to see any output, even if it fails, just do, or don't do, the thing" shortcut:

call-foo &> /dev/null

I think you have a small typo here.
Shouldn't it read

call-foo &> /dev/null
 

I would've done call-foo > out-and-error.txt 2> out-and-error.txt; I've never heard of 2>&1 or &>. Very cool! Thanks for that!

What would be a practical application of print stdout and stderr to the same file?

@fennecdjay
@thorstenhirsch
@sinewalker

Openssl prints diagnostic info to stderr and certificate info to stdout. If you want them both in the same filter stream, &> is very handy. Or if you want them all in the same single log file

 
 

Another really useful redirection-related BASHism: <( ):

Useful if, say, you want to check to see if a local file and an S3-hosted file are the same:

$ sha256sum <( aws s3 cp s3://BUKKIT1/file - ) ./file
d20c7a50c3ac734230b08dbe2cb9122634c2dd040eee56ebd8101bef455dbb88 */dev/fd/63
c204dbfa154fc4801bdaac298584815bbd1b4a968a2349dd17f1e7c459904d41 *file

Similarly, can be used for things like diffing two streams:

diff <( aws s3 cp s3://BUKKIT1/file - ) <( aws s3 cp s3://BUKKIT2/file - )
 

Another one people don't seem to use much is >| which will overwrite a file even if noclobber is on.

 

Makes truncating a breeze! |> logfile.log

 

I never looked these up before, though I use most of them almost everyday 😁

Thanks Pierson!

 

Haha, I was in the same boat!