Linux - SoftwareThis forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.

Notices

Welcome to LinuxQuestions.org, a friendly and active Linux Community.

You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!

Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.

If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.

Having a problem logging in? Please visit this page to clear all LQ-related cookies.

Introduction to Linux - A Hands on Guide

This guide was created as an overview of the Linux Operating System, geared toward new users as an exploration tour and getting started guide, with exercises at the end of each chapter.
For more advanced trainees it can be a desktop reference, and a collection of the base knowledge needed to proceed with system and network administration. This book contains many real life examples derived from the author's experience as a Linux system and network administrator, trainer and consultant. They hope these examples will help you to get a better understanding of the Linux system and that you feel encouraged to try out things on your own.

may not work as you expect it.
It is likely that you won't see the stderr and stdout messages in the order in which they were sent to your terminal, simply because stdout (file descriptor 1) is buffered and stderr (2) is not (or was that the other way around - I keep mixing that up). So you'll see the stderr messages first and then the stdout ones (or vice-versa).

If you want the stderr and stdout messages to appear in the right order, you'll need to use a subshell, like so:
(ls -l 2>&1) > file.txt
or
(ls -l 2>&1) | tee file.txt if you want it to appear on screen and in file.txt
This basically says that it should execute the ls -l command, sending stderr to stdout in a subshell. All output from the subshell then comes from the subshell's stdout, and you can capture it in a file or with "tee".
The subshell will only make sure that the stderr and stdout messages appear in the right order.

I have to admire you for running all these tests to try to learn. The three pieces I think you're missing in your analysis are "How many commands am I running?", "What order am I redirecting things in?" and "What does | do anyway?"

The first missing piece:
---

For example

Code:

./command.sh >file.txt 2>&1

is only running ONE command, namely "command.sh"

However

Code:

./command.sh 2>&1 | tee file.txt

is running TWO commands, namely "command.sh" and "tee"

When you are running more than one command, you have to remember that EACH command has it's own stdout and stderr. So depending on where you put that little "2>&1" thingy, for example, will determine whether you're redirecting stderr from "command.sh" or from "tee". The same goes for when you're running subshells. The subshell itself is a command so think about whether you're redirecting output from "command.sh" which is running within the subshell, or redirecting output from the subshell itself.

Example: ls -l >file.txt 2>&1 means "Send stdout to file.txt and send stderr to the same place as stdout

When we're talking ampersands, "to the same place as" has to also take into account "at this time"

Example

Code:

ls -l >file.txt 2>&1

will send both stdout and stderr to file.txt. Why? Because FIRST stdout was redirected to file.txt and THEN stderr was told to go to the same place as stdout.

On the other hand

Code:

ls -l 2>&1 >file.txt

will send stderr to your screen and stdout to file.txt. Why? Because stderr was redirected to the same place as stdout, but at this time stdout was still pointing to the console. stdout was not redirected to file.txt until AFTER stderr had been redirected. When we are talking AFTER in this example we are talking about placement on the command line. Things specified further to the right are thought of as coming after. So this example does nothing for stderr. stderr is indeed redirected to the same place as stdout, which is the console at the time of the redirection, but stderr was ALREADY pointing there in the first place - resulting in no perceivable change.

To the third missing piece:
---

The pipe symbol "|" can be thought of like a fancy redirection of stdout. It redirects stdout from the first command to the stdin of the second command. So ls -l | tee file.txt says "Take the stdout of ls and send it to the stdin of tee. "tee" is simply a program that takes its stdin and sends it to two places, stdout and also to a file.

The eagle-eyed observer will notice an apparent discrepancy for "|" ...

ls -l 2>&1 | tee file.txt will log BOTH stdout and stderr from ls to file.txt. But at this time, when stderr was redirected to the same place as stdout, stdout had not yet been redirected to tee via the "|". Hmmm ... gotcha! Just one of those things. Never fails - when you try to rationalize your way through something logically ... you run into an exception! This is one of those things were experience tells me "I know it works this way", but when you press me with the "why?" question, I have to hem and haw and say "Because that's the way it is!"

---

Now that you head is spining with this cryptic "explanation", maybe it will start making more sense why you're seeing what you're seeing in your tests.

Thanks haertig for the explanation! The results of the tests that i ran certainly makes sense now.

As for

Code:

ls -l 2>&1 | tee file.txt

Can we say that:
First, the stderr is redirected to where the stdout goes.
Then we send whatever "comes out" of where stdout normally "comes out", and send it to tee.
And since at that point, both stdout and stderr "comes out" of that place, both are piped to tee, which both displays and sends it to file.
?

Can we say that:
First, the stderr is redirected to where the stdout goes.
Then we send whatever "comes out" of where stdout normally "comes out", and send it to tee.
And since at that point, both stdout and stderr "comes out" of that place, both are piped to tee, which both displays and sends it to file.

Actually, I don't think that the ampersand strictly means "to the same place as". I think that the ampersand is necessary so that "1" isn't interpreted as a file.
The code

Code:

ls 1>1

will redirect stdout to a file named "1"
Whereas

Code:

ls 1>&1

will redirect stdout to stdout. :)

Good point, see REDIRECTION in bash man. As you can see, the manual is far from clear on this:

Quote:

The general format for redirecting output is:

[n]>word
[...]
>&word
[...] is semantically equiva‐
lent to

>word 2>&1
[...]
The operator

[n]>&word

is used similarly to duplicate output file descriptors. (That is: "If word expands to one or
more digits, the file descriptor denoted by n is made to be a copy of
that file descriptor.", doru's note) If n is not
specified, the standard output (file descriptor 1) is used. If the
digits in word do not specify a file descriptor open for output, a re‐
direction error occurs. As a special case, if n is omitted, and word
does not expand to one or more digits, the standard output and standard
error are redirected as described previously.

The eagle-eyed observer will notice an apparent discrepancy for "|" ...

ls -l 2>&1 | tee file.txt will log BOTH stdout and stderr from ls to file.txt. But at this time, when stderr was redirected to the same place as stdout, stdout had not yet been redirected to tee via the "|". Hmmm ... gotcha! Just one of those things. Never fails - when you try to rationalize your way through something logically ... you run into an exception! This is one of those things were experience tells me "I know it works this way", but when you press me with the "why?" question, I have to hem and haw and say "Because that's the way it is!"

It makes sense in the light of the shell's operation. The "|" is actioned in "3. Parses the tokens into simple and compound commands" and the ">"s are actioned in "5. Performs any necessary redirections ..." so, in this case, the ls command's stdout is already configured for redirection to the tee command by the time the ">"s are processed.

It makes sense in the light of the shell's operation. The "|" is actioned in "3. Parses the tokens into simple and compound commands" and the ">"s are actioned in "5. Performs any necessary redirections ..." so, in this case, the ls command's stdout is already configured for redirection to the tee command by the time the ">"s are processed.