LearnLinux FoundationsI/O Redirection

Merge Streams with 2>&1

2>&1 - a hands-on Linux lab on a real virtual machine.

Fold the error channel into stdout with 2&1. Merge both streams of a report into one file, learn why the order of redirections matters, then send errors through a pipe into a filter, all in the practice terminal.

You are still in the signal folder, and report.sh still says its three things: two lines of good news and one complaint about an offline sensor. Remember from the file descriptors lesson: the good news rides channel 1, stdout, and the complaint rides channel 2, stderr. And remember from the &> lesson: bash report.sh &> all.txt swept both channels into one file with a single arrow. It felt like magic.

Here is the puzzle hiding inside that magic. A command has no "both" channel. There are only the numbered ones, 1 and 2. So how did one operator catch two streams?

Your first instinct might be to aim each channel at the same file yourself: bash report.sh > both.txt 2> both.txt. Do not. That command opens the file twice, once per channel, and the two streams write over each other like two people typing on the same line. What you actually need is a way to say: channel 2, stop having your own destination, and follow channel 1 wherever it goes.

There is an operator that says exactly that. It is four characters long, it is the machinery hiding inside &>, and it can deliver both streams to a place &> cannot reach. This lesson is about those four characters.

The black boxes below are a practice terminal: a safe sandbox that only checks the one command each step teaches, so you cannot break anything. On the real machine at the end of the module, the mission builds this same signal folder, and you run these redirects for real.

The operator is 2>&1. Read it in three pieces:

The & is the crucial character. Without it, 2>1 would send the errors into a file named 1. With it, &1 means "the destination channel 1 is using right now," not a filename. So 2>&1 says: point stderr at the same place stdout goes. One door, both streams through it, and nothing gets overwritten, because only one destination is ever opened.

The spelling is nearly fifty years old. Steve Bourne's 1979 Unix shell introduced 2>&1 as the way to point one channel at another's destination, and every shell since has kept it, character for character.

Type 2>&1 as one solid block, no spaces anywhere inside it. Break it apart and the shell reads the pieces as separate redirects and arguments, and the merge never happens.

Time to do what &> did, by hand, so you can see the machinery. The plan has two moves, written left to right: first > both.txt points channel 1 at the file, then 2>&1 points channel 2 at wherever channel 1 goes, which is now that same file. Watch the flow:

{ "caption": "bash report.sh > both.txt 2>&1: first > aims channel 1 at the file, then 2>&1 folds channel 2 into the same destination.", "nodes": [ { "id": "cmd", "label": "report.sh", "kind": "command", "col": 0, "row": 1 }, { "id": "out", "label": "stdout (1)", "kind": "stdout", "col": 2, "row": 0 }, { "id": "err", "label": "stderr (2)", "kind": "stderr", "col": 2, "row": 2 }, { "id": "file", "label": "both.txt", "kind": "file", "col": 4, "row": 1 } ], "edges": [ { "from": "cmd", "to": "out", "label": "results", "kind": "stdout", "stage": 1 }, { "from": "cmd", "to": "err", "label": "complaint", "kind": "stderr", "stage": 1 }, { "from": "out", "to": "file", "label": "> both.txt", "kind": "stdout", "stage": 2 }, { "from": "err", "to": "file", "label": "2>&1", "kind": "stderr", "stage": 3 } ] }

Before you run it, decide what the screen will show. Both channels are pointed at the file, so how many of the three lines should survive on screen?

bash report.sh > both.txt 2>&1

prompt: student@linuxcamp:~/signal$ answer: bash report.sh > both.txt 2>&1 output: hint: Aim stdout at the file first, then fold stderr in: bash report.sh > both.txt 2>&1

A bare prompt. Zero lines survived, which is exactly right: channel 1 went into both.txt, and 2>&1 sent channel 2 chasing after it. Remember from the > lesson: when everything a command prints is redirected, the terminal stays silent. The proof of the merge is sitting inside the file.

Read both.txt back with cat. Commit first: how many lines do you expect to find, and which line comes last?

cat both.txt

prompt: student@linuxcamp:~/signal$ answer: cat both.txt output: report: system nominal report: all checks passed report: sensor offline hint: cat, a space, then the file both streams landed in: cat both.txt

All three lines in one file: the two stdout lines first, the stderr line last. Look at what you just built. In the 2> lesson the best you could manage was screen plus file. Now a single run leaves one complete record, results and complaint together, in order. And here is the unmasking: &> all.txt from last lesson is nothing but > all.txt 2>&1 with the machinery hidden. You can now write the long form by hand. That matters, because the shorthand is bash-only and file-only, while the long form works everywhere, and it is about to reach somewhere no filename can go.

One trap before you go further. The shell reads redirections left to right. 2>&1 means "where channel 1 points right now", not "where it will point later". Swap the two pieces and the meaning changes completely.

Replay the flow diagram above and watch the stages: the arrow into the file lights up first, and only then does the error stream fold in. That order is the whole rule.

Destination first, merge second: > file 2>&1. If a merged file keeps missing its error lines, check the order before anything else.

Here is the destination &> can never reach. So far every redirect has pointed at a file. But channel 1 can also point at another command, through a pipe: the | character feeds what the left command prints into the command on its right. The pipe gets its own full lesson two lessons from now; that one sentence is all you need today.

The catch that makes this a 2>&1 moment: a pipe carries only channel 1. Complaints on channel 2 sail right past it to your screen. If you want the tool on the right side of the pipe to see the errors too, you must fold channel 2 into channel 1 first, and now you know exactly how.

The tool on the right will be grep, which keeps only the lines containing a word you give it (its own lesson comes later in the track). Every line of the report contains the word report, so decide before you run: with the merge in place, how many lines should grep report let through?

bash report.sh 2>&1 | grep report

prompt: student@linuxcamp:~/signal$ answer: bash report.sh 2>&1 | grep report output: report: system nominal report: all checks passed report: sensor offline hint: Fold the channels together before the pipe: bash report.sh 2>&1 | grep report

Three lines through the filter, including the complaint. Notice where the merge sits: 2>&1 comes right after the command, BEFORE the |. By the time the shell applies it, channel 1 is already pointed into the pipe, so "follow channel 1" means "into the pipe you go." No file was involved anywhere. That is the move &> cannot write.

Skeptical? Good, that is an engineer's habit. The word offline appears in exactly one place: the complaint, the line that travels on channel 2. If the pipe were carrying only stdout, grep offline would print nothing at all. Commit to your prediction, then run the test:

bash report.sh 2>&1 | grep offline

prompt: student@linuxcamp:~/signal$ answer: bash report.sh 2>&1 | grep offline output: report: sensor offline hint: Same merge-then-pipe shape, but grep for offline: bash report.sh 2>&1 | grep offline

There it is: a filter just read an error message. That single line is the reason 2>&1 | is burned into every Linux engineer's fingers. Drop the 2>&1 and grep goes blind to channel 2: the complaint skips the pipe, splashes onto your screen unfiltered, and the search comes up empty. Merge first, then pipe, and nothing escapes. Time to prove you own the move, with the scaffolding removed.

No command is shown from here on.

The monitoring team wants a complete record: one run of the report, all three lines, results and complaint together, saved into both.txt. Their older servers do not have the bash shorthand, so write the long form.

prompt: student@linuxcamp:~/signal$ answer: bash report.sh > both.txt 2>&1 output: hint: Two moves, left to right: point channel 1 at the file, then fold channel 2 into it.

Silent prompt, full file. You just wrote the exact form shell scripts have used for decades to keep a command's errors next to its output.

Trust, then verify. Print the archive you just wrote and confirm the complaint is in there, riding last.

prompt: student@linuxcamp:~/signal$ answer: cat both.txt output: report: system nominal report: all checks passed report: sensor offline hint: The file-reading command you have used all module, pointed at the merged file.

Three lines, complaint last. The record is complete, and you proved it instead of assuming it.

The on-call engineer does not want an archive, just an answer: is anything offline? Ask the report directly, in one command, no file anywhere, and make sure the error channel cannot slip past your filter.

prompt: student@linuxcamp:~/signal$ answer: bash report.sh 2>&1 | grep offline output: report: sensor offline hint: Merge the channels before the pipe, then filter for the word offline.

One command, one answer, nothing missed. Three challenges from memory: the merge is yours now.

You earned this cheat sheet. Every row is something you just ran in the signal folder:

The one idea under all of it: 2>&1 does not name a place. It says "channel 2, go wherever channel 1 is going right now." Point channel 1 at a file and the errors follow it there. Point it into a pipe and the errors ride along. And &> from last lesson is just this move pre-packaged: bash spelling > file 2>&1 for you.

Two habits to keep. Destination first, merge second: > file 2>&1, never the other way around. And type 2>&1 as one solid block, no spaces inside.

You can now steer the two output channels together as well as apart. > and 2> split them, &> and > file 2>&1 merge them into a file, and 2>&1 | sends them both through a pipe. Next lesson adds /dev/null, the place you point a channel when you want it gone, and the pipe you previewed today gets its full lesson right after.

The I/O Redirection module ends with one real Linux machine: the redirection mission lab. There a VM boots just for you with this same signal folder and report.sh already in place, and the mission hands you objectives with no commands shown. You read the objective, recall the operator, and type it. That recall is what makes it stick.

Finish the other I/O Redirection lessons, then go merge the streams for real.

Practice Merge Streams with 2>&1 in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.