skip to Main Content

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


  1. 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?

    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,

    The standard output of command1 shall be connected to the standard input of command2. The standard input, standard output, or both of a command shall be considered to be assigned by the pipeline before any redirection specified by redirection operators that are part of the command

    (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:

    cat << EOF > arquivo.txt
    ola
    ola1
    EOF
    
    wc -l < arquivo.txt > linhas.txt
    
    # OR
    
    cat << EOF > arquivo.txt ; wc -l < arquivo.txt > linhas.txt
    ola
    ola1
    EOF
    

    If you want to use a pipeline to convey cat‘s output to wc, then drop the redirections that are getting in the way of that:

    cat << EOF | wc -l > linhas.txt
    ola
    ola1
    EOF
    

    That does result in arquivo.txt not being written, however. If you want to write arquivo.txt too then use tee instead of cat (or insert a tee command into the pipeline between cat and wc):

    tee arquivo.txt << EOF | wc -l > linhas.txt
    ola
    ola1
    EOF
    
    Login or Signup to reply.
  2. 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*:

    cat << EOF | tee arquivo.txt | wc -l > linhas.txt
    ola
    ola1
    EOF
    

    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 containing 2.

    You can also break up your commands into two commands, the first to create arquivo.txt and the second to create linhas.txt:

    cat << EOF > arquivo.txt
    ola
    ola1
    EOF
    wc -l < arquivo.txt > linhas.txt
    

    Notes:

    * Yes, I’m aware this is a Useless Use of Cat (UUOC).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search