I’m studying about pipes and redirects in Bash and came across a situation i can’t find an explanation about how bash processes its pipes and redirects.
I was testing this command:
cat << EOF > arquivo.txt | wc -l < arquivo.txt > linhas.txt
ola
ola1
EOF
And i was expecting it to give the output of 2 because it should have added to arquivo.txt file the user the text
ola
ola1
And should have added to linhas.txt the output of wc -l < arquivo.txt witch should have been 2 but instead of that the output of the command it’s 0 and if i execute the commands separately without the pipes its working as it should.
I couldn’t find any explanation online about it and want to know more about how bash parses and executes the pipes as my only theory is that the pipes are executed independently and not caring about if the commands before the pipe were executed completely witch its a bit counterintuitive for me.
Is that the truth or am I missing something?
2
Answers
You have only one pipe, so I guess you are hypothesizing that the commands on the two ends of a pipe may be executed independently. Yes, they are (mostly). The idea is that they run at the same time, with the standard output of the command on the left fed into the standard input of the one on the right.
That the one command reads the output of the other ordinarily creates some synchronization between the two, but you have suppressed that by overriding the pipe with redirections inside the commands on both ends. Per the POSIX specifications for the shell language,
(Emphasis added).
The Bash manual contains similar text, but it is unclear about the ordering with respect to the redirections of the second command.
If you want one command to run to completion before the other starts, without connecting their standard streams, then just run one after the other, without a pipeline:
If you want to use a pipeline to convey
cat
‘s output towc
, then drop the redirections that are getting in the way of that:That does result in
arquivo.txt
not being written, however. If you want to writearquivo.txt
too then usetee
instead ofcat
(or insert atee
command into the pipeline betweencat
andwc
):There’s more than one way to do it.
Try using
tee
to write the pipe’s contents to an intermediate file and re-echo the piped lines*:Each program after the pipe will receive the full list. However if you were to add another pipe and program after
wc
instead of redirecting to the file, it would only receive one line containing2
.You can also break up your commands into two commands, the first to create
arquivo.txt
and the second to createlinhas.txt
:Notes:
* Yes, I’m aware this is a Useless Use of Cat (UUOC).