The ‘tee’ command has a bug

uestc_alayi

New Member
Credits
25
J[%}PI(T4AOJA{Z[`MHVHR6.png

G}C[T~QD661}XDY74}C3EIQ.png

BYZY99XV8ML4JWA7GI0OBKJ.png

When I did not create the file junk2 by any means, the output of ls | wc -w was the same as the output of ls | wc -w | tee junk2. When I delete the (rm) junk2 file and output the same command again, the results of the two are inconsistent
 


JasKinasis

Well-Known Member
Credits
939
There isn't a bug at all. What you are seeing is typical behaviour from the shell.

Very often, when you enter a piped command like that - the output file will be created by the shell interpreter BEFORE the first command is executed. So the shell will create the junk2 file before the first command is executed, so it is ready for tee to write to it.
So your command:
Bash:
ls | wc -w | tee junk2
junk2 will usually be created BEFORE the ls command is executed. But it's not always guaranteed, as you saw with some of your results.

If you're doing something like the above, using the ls command - then to avoid this problem, it's usually best to create any output files OUTSIDE of the directory you're working in.
e.g.
Bash:
ls | wc -w | tee /path/to/junk2
Where /path/to/junk2 is a path that is NOT the current working directory.

OR, if the file MUST be in the current working directory, then you could do something like this:
Bash:
ls | \grep -vw junk2 | wc -w | tee junk2
In the above - if the output file IS created by the shell BEFORE the ls command is ran - we can remove it from the listing using \grep BEFORE piping it to tee, which writes the output of the previous commands to the file.

And the reason I'm using \grep instead of grep is to escape any aliases that might be set up in the users .bashrc. Very often grep will be aliased to use various options to add line numbers to it's output, or to colourise output, or to add other types of formatting. So by using \grep, we can be 100% sure that the output from grep will just be filenames that were piped in by the previous ls command.

Many Linux distros set up aliases in users default .bashrc files for common commands like ls, grep etc.
So if you want to be sure that you're getting exactly what you're asking for, with no extra guff - then prepend the command with a backslash and you can escape any aliases that have been set-up!

I hope that clears things up!
 

uestc_alayi

New Member
Credits
25
There isn't a bug at all. What you are seeing is typical behaviour from the shell.

Very often, when you enter a piped command like that - the output file will be created by the shell interpreter BEFORE the first command is executed. So the shell will create the junk2 file before the first command is executed, so it is ready for tee to write to it.
So your command:
Bash:
ls | wc -w | tee junk2
junk2 will usually be created BEFORE the ls command is executed. But it's not always guaranteed, as you saw with some of your results.

If you're doing something like the above, using the ls command - then to avoid this problem, it's usually best to create any output files OUTSIDE of the directory you're working in.
e.g.
Bash:
ls | wc -w | tee /path/to/junk2
Where /path/to/junk2 is a path that is NOT the current working directory.

OR, if the file MUST be in the current working directory, then you could do something like this:
Bash:
ls | \grep -vw junk2 | wc -w | tee junk2
In the above - if the output file IS created by the shell BEFORE the ls command is ran - we can remove it from the listing using \grep BEFORE piping it to tee, which writes the output of the previous commands to the file.

And the reason I'm using \grep instead of grep is to escape any aliases that might be set up in the users .bashrc. Very often grep will be aliased to use various options to add line numbers to it's output, or to colourise output, or to add other types of formatting. So by using \grep, we can be 100% sure that the output from grep will just be filenames that were piped in by the previous ls command.

Many Linux distros set up aliases in users default .bashrc files for common commands like ls, grep etc.
So if you want to be sure that you're getting exactly what you're asking for, with no extra guff - then prepend the command with a backslash and you can escape any aliases that have been set-up!

I hope that clears things up!
But the result of my first use is correct. After deleting junk2 with the rm command, it is wrong to use the ls | wc -w | tee junk2 command again?
Similarly, I use the touch command to create the file kk, and then delete the file kk. The result of using'ls | wc -w' is different from the result of using'ls | wc -w | tee kk'
What caused it?
 

uestc_alayi

New Member
Credits
25
There isn't a bug at all. What you are seeing is typical behaviour from the shell.

Very often, when you enter a piped command like that - the output file will be created by the shell interpreter BEFORE the first command is executed. So the shell will create the junk2 file before the first command is executed, so it is ready for tee to write to it.
So your command:
Bash:
ls | wc -w | tee junk2
junk2 will usually be created BEFORE the ls command is executed. But it's not always guaranteed, as you saw with some of your results.

If you're doing something like the above, using the ls command - then to avoid this problem, it's usually best to create any output files OUTSIDE of the directory you're working in.
e.g.
Bash:
ls | wc -w | tee /path/to/junk2
Where /path/to/junk2 is a path that is NOT the current working directory.

OR, if the file MUST be in the current working directory, then you could do something like this:
Bash:
ls | \grep -vw junk2 | wc -w | tee junk2
In the above - if the output file IS created by the shell BEFORE the ls command is ran - we can remove it from the listing using \grep BEFORE piping it to tee, which writes the output of the previous commands to the file.

And the reason I'm using \grep instead of grep is to escape any aliases that might be set up in the users .bashrc. Very often grep will be aliased to use various options to add line numbers to it's output, or to colourise output, or to add other types of formatting. So by using \grep, we can be 100% sure that the output from grep will just be filenames that were piped in by the previous ls command.

Many Linux distros set up aliases in users default .bashrc files for common commands like ls, grep etc.
So if you want to be sure that you're getting exactly what you're asking for, with no extra guff - then prepend the command with a backslash and you can escape any aliases that have been set-up!

I hope that clears things up!
Why is it wrong to use the command again after deleting the file with rm?
 

JasKinasis

Well-Known Member
Credits
939
Read my post again, very carefully.
I’ve explained it all there.
The command isn’t wrong. But there is no bug either. It’s typical shell behaviour.

With a piped command like the one you posted - the shell will usually try to create the output file BEFORE the first command is ran.
But - if there is something blocking the write, like another process which is writing to disk - then the file creation may end up happening AFTER the first command is executed.
So the file is not guaranteed to be created before the first command is ran.

In these cases - the output file is probably cached in a disk buffer, waiting to be written to disk when the ls command runs.

So on your first run of your command - perhaps there was something that blocked the file write. Perhaps the file could not be written to disk immediately and it was still in a disk buffer when your ls command was ran. That is the reason you’re seeing different results sometimes.

Does that make sense?!
 


Members online


Latest posts

Top