grep doesn't output until EOF if piped through cat

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
20
down vote

favorite
5












Given this minimal example



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )


it outputs LINE 1 and then, after one second, outputs LINE 2, as expected.




If we pipe this to grep LINE



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE


the behavior is the same as in the previous case, as expected.




If, alternatively, we pipe this to cat



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat


the behavior is again the same, as expected.




However, if we pipe to grep LINE, and then to cat,



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat


there is no output until one second passes, and both lines appear on the output immediately, which I did not expect.




Why is this happening and how can I make the last version to behave in the same way as the first three commands?










share|improve this question





















  • cat concatenates files. What are you trying to do by piping into cat?
    – Douglas Held
    Sep 5 at 20:09






  • 15




    @DouglasHeld When called without arguments, cat simply reads stdin and outputs into stdout. Of course, I came up with this question with a lot of complex stuff in place of echo and cat, but these turned out to be irrelevant, since the problem shows up with much simpler examples.
    – lisyarus
    Sep 5 at 21:11






  • 3




    @DouglasHeld: Piping to cat is often useful to force stdout to not be a terminal. For instance, this is an easy way to get many commands to not use colorized output.
    – wchargin
    Sep 7 at 5:01










  • I swear this is a dupliciate of another question on Stack Overflow!
    – iBug
    Sep 7 at 6:46















up vote
20
down vote

favorite
5












Given this minimal example



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )


it outputs LINE 1 and then, after one second, outputs LINE 2, as expected.




If we pipe this to grep LINE



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE


the behavior is the same as in the previous case, as expected.




If, alternatively, we pipe this to cat



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat


the behavior is again the same, as expected.




However, if we pipe to grep LINE, and then to cat,



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat


there is no output until one second passes, and both lines appear on the output immediately, which I did not expect.




Why is this happening and how can I make the last version to behave in the same way as the first three commands?










share|improve this question





















  • cat concatenates files. What are you trying to do by piping into cat?
    – Douglas Held
    Sep 5 at 20:09






  • 15




    @DouglasHeld When called without arguments, cat simply reads stdin and outputs into stdout. Of course, I came up with this question with a lot of complex stuff in place of echo and cat, but these turned out to be irrelevant, since the problem shows up with much simpler examples.
    – lisyarus
    Sep 5 at 21:11






  • 3




    @DouglasHeld: Piping to cat is often useful to force stdout to not be a terminal. For instance, this is an easy way to get many commands to not use colorized output.
    – wchargin
    Sep 7 at 5:01










  • I swear this is a dupliciate of another question on Stack Overflow!
    – iBug
    Sep 7 at 6:46













up vote
20
down vote

favorite
5









up vote
20
down vote

favorite
5






5





Given this minimal example



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )


it outputs LINE 1 and then, after one second, outputs LINE 2, as expected.




If we pipe this to grep LINE



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE


the behavior is the same as in the previous case, as expected.




If, alternatively, we pipe this to cat



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat


the behavior is again the same, as expected.




However, if we pipe to grep LINE, and then to cat,



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat


there is no output until one second passes, and both lines appear on the output immediately, which I did not expect.




Why is this happening and how can I make the last version to behave in the same way as the first three commands?










share|improve this question













Given this minimal example



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )


it outputs LINE 1 and then, after one second, outputs LINE 2, as expected.




If we pipe this to grep LINE



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE


the behavior is the same as in the previous case, as expected.




If, alternatively, we pipe this to cat



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat


the behavior is again the same, as expected.




However, if we pipe to grep LINE, and then to cat,



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat


there is no output until one second passes, and both lines appear on the output immediately, which I did not expect.




Why is this happening and how can I make the last version to behave in the same way as the first three commands?







bash grep pipe






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Sep 5 at 15:08









lisyarus

20316




20316











  • cat concatenates files. What are you trying to do by piping into cat?
    – Douglas Held
    Sep 5 at 20:09






  • 15




    @DouglasHeld When called without arguments, cat simply reads stdin and outputs into stdout. Of course, I came up with this question with a lot of complex stuff in place of echo and cat, but these turned out to be irrelevant, since the problem shows up with much simpler examples.
    – lisyarus
    Sep 5 at 21:11






  • 3




    @DouglasHeld: Piping to cat is often useful to force stdout to not be a terminal. For instance, this is an easy way to get many commands to not use colorized output.
    – wchargin
    Sep 7 at 5:01










  • I swear this is a dupliciate of another question on Stack Overflow!
    – iBug
    Sep 7 at 6:46

















  • cat concatenates files. What are you trying to do by piping into cat?
    – Douglas Held
    Sep 5 at 20:09






  • 15




    @DouglasHeld When called without arguments, cat simply reads stdin and outputs into stdout. Of course, I came up with this question with a lot of complex stuff in place of echo and cat, but these turned out to be irrelevant, since the problem shows up with much simpler examples.
    – lisyarus
    Sep 5 at 21:11






  • 3




    @DouglasHeld: Piping to cat is often useful to force stdout to not be a terminal. For instance, this is an easy way to get many commands to not use colorized output.
    – wchargin
    Sep 7 at 5:01










  • I swear this is a dupliciate of another question on Stack Overflow!
    – iBug
    Sep 7 at 6:46
















cat concatenates files. What are you trying to do by piping into cat?
– Douglas Held
Sep 5 at 20:09




cat concatenates files. What are you trying to do by piping into cat?
– Douglas Held
Sep 5 at 20:09




15




15




@DouglasHeld When called without arguments, cat simply reads stdin and outputs into stdout. Of course, I came up with this question with a lot of complex stuff in place of echo and cat, but these turned out to be irrelevant, since the problem shows up with much simpler examples.
– lisyarus
Sep 5 at 21:11




@DouglasHeld When called without arguments, cat simply reads stdin and outputs into stdout. Of course, I came up with this question with a lot of complex stuff in place of echo and cat, but these turned out to be irrelevant, since the problem shows up with much simpler examples.
– lisyarus
Sep 5 at 21:11




3




3




@DouglasHeld: Piping to cat is often useful to force stdout to not be a terminal. For instance, this is an easy way to get many commands to not use colorized output.
– wchargin
Sep 7 at 5:01




@DouglasHeld: Piping to cat is often useful to force stdout to not be a terminal. For instance, this is an easy way to get many commands to not use colorized output.
– wchargin
Sep 7 at 5:01












I swear this is a dupliciate of another question on Stack Overflow!
– iBug
Sep 7 at 6:46





I swear this is a dupliciate of another question on Stack Overflow!
– iBug
Sep 7 at 6:46











3 Answers
3






active

oldest

votes

















up vote
39
down vote



accepted










When (at least GNU) grep’s output is not a terminal, it buffers its output, which is what causes the behaviour you’re seeing. You can disable this either using GNU grep’s --line-buffered option:



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat


or the stdbuf utility:



( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat


Turn off buffering in pipe has more on this topic.






share|improve this answer



























    up vote
    26
    down vote













    Simplified explanation



    Like many utilities, this not being something peculiar to one program, grep varies its standard output between being line buffered and fully buffered. In the former case, the C library buffers output data in memory until either the buffer holding those data is filled or a linefeed character is added to it (or the program ends cleanly), whereupon it calls write() to actually write the buffer contents. In the latter case, only the in-memory buffer becoming full (or the program ending cleanly) triggers the write().



    More detailed explanation



    This is the well-known, but slightly wrong, explanation. In fact, standard output is not line buffered but smart buffered in the GNU C library and BSD C library. Standard output is also flushed when reading standard input exhausts its in-memory buffer (of pre-read input) and the C library has to call read() to fetch some more input and it is reading the beginning of a new line. (One reason for this is to prevent deadlock when another program connects itself to both ends of a filter and expects to be able to operate line-by-line, alternating between writing to the filter and reading from it; like "coprocesses" in GNU awk for example.)



    C library influence



    grep and the other utilities do this — or, more strictly, the C libraries that they use do this, because this is a defined feature of programming in the C language — based upon what they detect their standard output to be. If (and only if) it is not an interactive device, they choose full buffering, otherwise they choose smart buffering. A pipe is considered to be not an interactive device, because the definition of being an interactive device, at least in the world of Unix and Linux, is essentially the isatty() call returning true for the relevant file descriptor.



    Workarounds to disable full buffering



    Some utilities like grep have idiosyncratic options such as --line-buffered that change this decision, which as you can see is mis-named. But a vanishingly small fraction of the filter programs that one could use actually have such an option.



    More generally, one can use tools that dig into the specific internals of the C library and change its decision making (which have security problems if the program to be altered is set-UID, and are also specific to particular C libraries, and indeed are specific to programs written in or layered on top of the C language), or tools such as ptybandage that do not change the internals of the program but simply interpose a pseudo-terminal as standard output so that the decision comes out as "interactive", to affect this.



    Further reading



    • https://unix.stackexchange.com/a/407472/5132

    • https://unix.stackexchange.com/a/249801/5132





    share|improve this answer






















    • Underrated answer. Thanks for the info!
      – Délisson Junio
      Sep 5 at 17:37






    • 1




      If the phrase "line buffered" is a misnomer, then it's not really the fault of grep, but of the underlying library calls, setbuf/setvbuf. I don't know of a reliable online reference for the C standard, but e.g. the Linux and FreeBSD man pages along with the POSIX description of setvbuf call it "line buffered". Even the symbolic constant for it is _IOLBF.
      – ilkkachu
      Sep 5 at 21:19










    • Well now you've learned better. This buffering strategy is described in the GNU C library doco, albeit briefly. Laurent Bercot is more forthright on the matter. I have mentioned it too.
      – JdeBP
      Sep 6 at 0:35






    • 2




      @ilkkachu The C standard does indeed use "line buffered". Per 7.21.3 Files, paragraph 3: "When a stream is unbuffered, ... When a stream is fully buffered, ... When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. ..." In fact, the C Standard uses the exact phrase "line buffered" five times. So it's not a misnomer.
      – Andrew Henle
      Sep 6 at 14:41







    • 1




      Furthermore, the approach described here as "smart buffering", as I understand it, seems to be just what the C standard describes as "line buffering". Specifically, in addition to flushing the buffer at newlines, "When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when [...] input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment." So this is not a GNU or BSD quirk, but rather what the language calls for.
      – John Bollinger
      Sep 6 at 22:44


















    up vote
    7
    down vote













    Use



    grep --line-buffered


    to make grep not buffer more than one line at a time.






    share|improve this answer




















      Your Answer







      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "106"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f467039%2fgrep-doesnt-output-until-eof-if-piped-through-cat%23new-answer', 'question_page');

      );

      Post as a guest






























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      39
      down vote



      accepted










      When (at least GNU) grep’s output is not a terminal, it buffers its output, which is what causes the behaviour you’re seeing. You can disable this either using GNU grep’s --line-buffered option:



      ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat


      or the stdbuf utility:



      ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat


      Turn off buffering in pipe has more on this topic.






      share|improve this answer
























        up vote
        39
        down vote



        accepted










        When (at least GNU) grep’s output is not a terminal, it buffers its output, which is what causes the behaviour you’re seeing. You can disable this either using GNU grep’s --line-buffered option:



        ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat


        or the stdbuf utility:



        ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat


        Turn off buffering in pipe has more on this topic.






        share|improve this answer






















          up vote
          39
          down vote



          accepted







          up vote
          39
          down vote



          accepted






          When (at least GNU) grep’s output is not a terminal, it buffers its output, which is what causes the behaviour you’re seeing. You can disable this either using GNU grep’s --line-buffered option:



          ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat


          or the stdbuf utility:



          ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat


          Turn off buffering in pipe has more on this topic.






          share|improve this answer












          When (at least GNU) grep’s output is not a terminal, it buffers its output, which is what causes the behaviour you’re seeing. You can disable this either using GNU grep’s --line-buffered option:



          ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat


          or the stdbuf utility:



          ( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat


          Turn off buffering in pipe has more on this topic.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Sep 5 at 15:12









          Stephen Kitt

          147k22321389




          147k22321389






















              up vote
              26
              down vote













              Simplified explanation



              Like many utilities, this not being something peculiar to one program, grep varies its standard output between being line buffered and fully buffered. In the former case, the C library buffers output data in memory until either the buffer holding those data is filled or a linefeed character is added to it (or the program ends cleanly), whereupon it calls write() to actually write the buffer contents. In the latter case, only the in-memory buffer becoming full (or the program ending cleanly) triggers the write().



              More detailed explanation



              This is the well-known, but slightly wrong, explanation. In fact, standard output is not line buffered but smart buffered in the GNU C library and BSD C library. Standard output is also flushed when reading standard input exhausts its in-memory buffer (of pre-read input) and the C library has to call read() to fetch some more input and it is reading the beginning of a new line. (One reason for this is to prevent deadlock when another program connects itself to both ends of a filter and expects to be able to operate line-by-line, alternating between writing to the filter and reading from it; like "coprocesses" in GNU awk for example.)



              C library influence



              grep and the other utilities do this — or, more strictly, the C libraries that they use do this, because this is a defined feature of programming in the C language — based upon what they detect their standard output to be. If (and only if) it is not an interactive device, they choose full buffering, otherwise they choose smart buffering. A pipe is considered to be not an interactive device, because the definition of being an interactive device, at least in the world of Unix and Linux, is essentially the isatty() call returning true for the relevant file descriptor.



              Workarounds to disable full buffering



              Some utilities like grep have idiosyncratic options such as --line-buffered that change this decision, which as you can see is mis-named. But a vanishingly small fraction of the filter programs that one could use actually have such an option.



              More generally, one can use tools that dig into the specific internals of the C library and change its decision making (which have security problems if the program to be altered is set-UID, and are also specific to particular C libraries, and indeed are specific to programs written in or layered on top of the C language), or tools such as ptybandage that do not change the internals of the program but simply interpose a pseudo-terminal as standard output so that the decision comes out as "interactive", to affect this.



              Further reading



              • https://unix.stackexchange.com/a/407472/5132

              • https://unix.stackexchange.com/a/249801/5132





              share|improve this answer






















              • Underrated answer. Thanks for the info!
                – Délisson Junio
                Sep 5 at 17:37






              • 1




                If the phrase "line buffered" is a misnomer, then it's not really the fault of grep, but of the underlying library calls, setbuf/setvbuf. I don't know of a reliable online reference for the C standard, but e.g. the Linux and FreeBSD man pages along with the POSIX description of setvbuf call it "line buffered". Even the symbolic constant for it is _IOLBF.
                – ilkkachu
                Sep 5 at 21:19










              • Well now you've learned better. This buffering strategy is described in the GNU C library doco, albeit briefly. Laurent Bercot is more forthright on the matter. I have mentioned it too.
                – JdeBP
                Sep 6 at 0:35






              • 2




                @ilkkachu The C standard does indeed use "line buffered". Per 7.21.3 Files, paragraph 3: "When a stream is unbuffered, ... When a stream is fully buffered, ... When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. ..." In fact, the C Standard uses the exact phrase "line buffered" five times. So it's not a misnomer.
                – Andrew Henle
                Sep 6 at 14:41







              • 1




                Furthermore, the approach described here as "smart buffering", as I understand it, seems to be just what the C standard describes as "line buffering". Specifically, in addition to flushing the buffer at newlines, "When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when [...] input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment." So this is not a GNU or BSD quirk, but rather what the language calls for.
                – John Bollinger
                Sep 6 at 22:44















              up vote
              26
              down vote













              Simplified explanation



              Like many utilities, this not being something peculiar to one program, grep varies its standard output between being line buffered and fully buffered. In the former case, the C library buffers output data in memory until either the buffer holding those data is filled or a linefeed character is added to it (or the program ends cleanly), whereupon it calls write() to actually write the buffer contents. In the latter case, only the in-memory buffer becoming full (or the program ending cleanly) triggers the write().



              More detailed explanation



              This is the well-known, but slightly wrong, explanation. In fact, standard output is not line buffered but smart buffered in the GNU C library and BSD C library. Standard output is also flushed when reading standard input exhausts its in-memory buffer (of pre-read input) and the C library has to call read() to fetch some more input and it is reading the beginning of a new line. (One reason for this is to prevent deadlock when another program connects itself to both ends of a filter and expects to be able to operate line-by-line, alternating between writing to the filter and reading from it; like "coprocesses" in GNU awk for example.)



              C library influence



              grep and the other utilities do this — or, more strictly, the C libraries that they use do this, because this is a defined feature of programming in the C language — based upon what they detect their standard output to be. If (and only if) it is not an interactive device, they choose full buffering, otherwise they choose smart buffering. A pipe is considered to be not an interactive device, because the definition of being an interactive device, at least in the world of Unix and Linux, is essentially the isatty() call returning true for the relevant file descriptor.



              Workarounds to disable full buffering



              Some utilities like grep have idiosyncratic options such as --line-buffered that change this decision, which as you can see is mis-named. But a vanishingly small fraction of the filter programs that one could use actually have such an option.



              More generally, one can use tools that dig into the specific internals of the C library and change its decision making (which have security problems if the program to be altered is set-UID, and are also specific to particular C libraries, and indeed are specific to programs written in or layered on top of the C language), or tools such as ptybandage that do not change the internals of the program but simply interpose a pseudo-terminal as standard output so that the decision comes out as "interactive", to affect this.



              Further reading



              • https://unix.stackexchange.com/a/407472/5132

              • https://unix.stackexchange.com/a/249801/5132





              share|improve this answer






















              • Underrated answer. Thanks for the info!
                – Délisson Junio
                Sep 5 at 17:37






              • 1




                If the phrase "line buffered" is a misnomer, then it's not really the fault of grep, but of the underlying library calls, setbuf/setvbuf. I don't know of a reliable online reference for the C standard, but e.g. the Linux and FreeBSD man pages along with the POSIX description of setvbuf call it "line buffered". Even the symbolic constant for it is _IOLBF.
                – ilkkachu
                Sep 5 at 21:19










              • Well now you've learned better. This buffering strategy is described in the GNU C library doco, albeit briefly. Laurent Bercot is more forthright on the matter. I have mentioned it too.
                – JdeBP
                Sep 6 at 0:35






              • 2




                @ilkkachu The C standard does indeed use "line buffered". Per 7.21.3 Files, paragraph 3: "When a stream is unbuffered, ... When a stream is fully buffered, ... When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. ..." In fact, the C Standard uses the exact phrase "line buffered" five times. So it's not a misnomer.
                – Andrew Henle
                Sep 6 at 14:41







              • 1




                Furthermore, the approach described here as "smart buffering", as I understand it, seems to be just what the C standard describes as "line buffering". Specifically, in addition to flushing the buffer at newlines, "When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when [...] input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment." So this is not a GNU or BSD quirk, but rather what the language calls for.
                – John Bollinger
                Sep 6 at 22:44













              up vote
              26
              down vote










              up vote
              26
              down vote









              Simplified explanation



              Like many utilities, this not being something peculiar to one program, grep varies its standard output between being line buffered and fully buffered. In the former case, the C library buffers output data in memory until either the buffer holding those data is filled or a linefeed character is added to it (or the program ends cleanly), whereupon it calls write() to actually write the buffer contents. In the latter case, only the in-memory buffer becoming full (or the program ending cleanly) triggers the write().



              More detailed explanation



              This is the well-known, but slightly wrong, explanation. In fact, standard output is not line buffered but smart buffered in the GNU C library and BSD C library. Standard output is also flushed when reading standard input exhausts its in-memory buffer (of pre-read input) and the C library has to call read() to fetch some more input and it is reading the beginning of a new line. (One reason for this is to prevent deadlock when another program connects itself to both ends of a filter and expects to be able to operate line-by-line, alternating between writing to the filter and reading from it; like "coprocesses" in GNU awk for example.)



              C library influence



              grep and the other utilities do this — or, more strictly, the C libraries that they use do this, because this is a defined feature of programming in the C language — based upon what they detect their standard output to be. If (and only if) it is not an interactive device, they choose full buffering, otherwise they choose smart buffering. A pipe is considered to be not an interactive device, because the definition of being an interactive device, at least in the world of Unix and Linux, is essentially the isatty() call returning true for the relevant file descriptor.



              Workarounds to disable full buffering



              Some utilities like grep have idiosyncratic options such as --line-buffered that change this decision, which as you can see is mis-named. But a vanishingly small fraction of the filter programs that one could use actually have such an option.



              More generally, one can use tools that dig into the specific internals of the C library and change its decision making (which have security problems if the program to be altered is set-UID, and are also specific to particular C libraries, and indeed are specific to programs written in or layered on top of the C language), or tools such as ptybandage that do not change the internals of the program but simply interpose a pseudo-terminal as standard output so that the decision comes out as "interactive", to affect this.



              Further reading



              • https://unix.stackexchange.com/a/407472/5132

              • https://unix.stackexchange.com/a/249801/5132





              share|improve this answer














              Simplified explanation



              Like many utilities, this not being something peculiar to one program, grep varies its standard output between being line buffered and fully buffered. In the former case, the C library buffers output data in memory until either the buffer holding those data is filled or a linefeed character is added to it (or the program ends cleanly), whereupon it calls write() to actually write the buffer contents. In the latter case, only the in-memory buffer becoming full (or the program ending cleanly) triggers the write().



              More detailed explanation



              This is the well-known, but slightly wrong, explanation. In fact, standard output is not line buffered but smart buffered in the GNU C library and BSD C library. Standard output is also flushed when reading standard input exhausts its in-memory buffer (of pre-read input) and the C library has to call read() to fetch some more input and it is reading the beginning of a new line. (One reason for this is to prevent deadlock when another program connects itself to both ends of a filter and expects to be able to operate line-by-line, alternating between writing to the filter and reading from it; like "coprocesses" in GNU awk for example.)



              C library influence



              grep and the other utilities do this — or, more strictly, the C libraries that they use do this, because this is a defined feature of programming in the C language — based upon what they detect their standard output to be. If (and only if) it is not an interactive device, they choose full buffering, otherwise they choose smart buffering. A pipe is considered to be not an interactive device, because the definition of being an interactive device, at least in the world of Unix and Linux, is essentially the isatty() call returning true for the relevant file descriptor.



              Workarounds to disable full buffering



              Some utilities like grep have idiosyncratic options such as --line-buffered that change this decision, which as you can see is mis-named. But a vanishingly small fraction of the filter programs that one could use actually have such an option.



              More generally, one can use tools that dig into the specific internals of the C library and change its decision making (which have security problems if the program to be altered is set-UID, and are also specific to particular C libraries, and indeed are specific to programs written in or layered on top of the C language), or tools such as ptybandage that do not change the internals of the program but simply interpose a pseudo-terminal as standard output so that the decision comes out as "interactive", to affect this.



              Further reading



              • https://unix.stackexchange.com/a/407472/5132

              • https://unix.stackexchange.com/a/249801/5132






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Sep 6 at 14:25









              Anthony Geoghegan

              7,30733852




              7,30733852










              answered Sep 5 at 15:51









              JdeBP

              29.6k460136




              29.6k460136











              • Underrated answer. Thanks for the info!
                – Délisson Junio
                Sep 5 at 17:37






              • 1




                If the phrase "line buffered" is a misnomer, then it's not really the fault of grep, but of the underlying library calls, setbuf/setvbuf. I don't know of a reliable online reference for the C standard, but e.g. the Linux and FreeBSD man pages along with the POSIX description of setvbuf call it "line buffered". Even the symbolic constant for it is _IOLBF.
                – ilkkachu
                Sep 5 at 21:19










              • Well now you've learned better. This buffering strategy is described in the GNU C library doco, albeit briefly. Laurent Bercot is more forthright on the matter. I have mentioned it too.
                – JdeBP
                Sep 6 at 0:35






              • 2




                @ilkkachu The C standard does indeed use "line buffered". Per 7.21.3 Files, paragraph 3: "When a stream is unbuffered, ... When a stream is fully buffered, ... When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. ..." In fact, the C Standard uses the exact phrase "line buffered" five times. So it's not a misnomer.
                – Andrew Henle
                Sep 6 at 14:41







              • 1




                Furthermore, the approach described here as "smart buffering", as I understand it, seems to be just what the C standard describes as "line buffering". Specifically, in addition to flushing the buffer at newlines, "When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when [...] input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment." So this is not a GNU or BSD quirk, but rather what the language calls for.
                – John Bollinger
                Sep 6 at 22:44

















              • Underrated answer. Thanks for the info!
                – Délisson Junio
                Sep 5 at 17:37






              • 1




                If the phrase "line buffered" is a misnomer, then it's not really the fault of grep, but of the underlying library calls, setbuf/setvbuf. I don't know of a reliable online reference for the C standard, but e.g. the Linux and FreeBSD man pages along with the POSIX description of setvbuf call it "line buffered". Even the symbolic constant for it is _IOLBF.
                – ilkkachu
                Sep 5 at 21:19










              • Well now you've learned better. This buffering strategy is described in the GNU C library doco, albeit briefly. Laurent Bercot is more forthright on the matter. I have mentioned it too.
                – JdeBP
                Sep 6 at 0:35






              • 2




                @ilkkachu The C standard does indeed use "line buffered". Per 7.21.3 Files, paragraph 3: "When a stream is unbuffered, ... When a stream is fully buffered, ... When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. ..." In fact, the C Standard uses the exact phrase "line buffered" five times. So it's not a misnomer.
                – Andrew Henle
                Sep 6 at 14:41







              • 1




                Furthermore, the approach described here as "smart buffering", as I understand it, seems to be just what the C standard describes as "line buffering". Specifically, in addition to flushing the buffer at newlines, "When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when [...] input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment." So this is not a GNU or BSD quirk, but rather what the language calls for.
                – John Bollinger
                Sep 6 at 22:44
















              Underrated answer. Thanks for the info!
              – Délisson Junio
              Sep 5 at 17:37




              Underrated answer. Thanks for the info!
              – Délisson Junio
              Sep 5 at 17:37




              1




              1




              If the phrase "line buffered" is a misnomer, then it's not really the fault of grep, but of the underlying library calls, setbuf/setvbuf. I don't know of a reliable online reference for the C standard, but e.g. the Linux and FreeBSD man pages along with the POSIX description of setvbuf call it "line buffered". Even the symbolic constant for it is _IOLBF.
              – ilkkachu
              Sep 5 at 21:19




              If the phrase "line buffered" is a misnomer, then it's not really the fault of grep, but of the underlying library calls, setbuf/setvbuf. I don't know of a reliable online reference for the C standard, but e.g. the Linux and FreeBSD man pages along with the POSIX description of setvbuf call it "line buffered". Even the symbolic constant for it is _IOLBF.
              – ilkkachu
              Sep 5 at 21:19












              Well now you've learned better. This buffering strategy is described in the GNU C library doco, albeit briefly. Laurent Bercot is more forthright on the matter. I have mentioned it too.
              – JdeBP
              Sep 6 at 0:35




              Well now you've learned better. This buffering strategy is described in the GNU C library doco, albeit briefly. Laurent Bercot is more forthright on the matter. I have mentioned it too.
              – JdeBP
              Sep 6 at 0:35




              2




              2




              @ilkkachu The C standard does indeed use "line buffered". Per 7.21.3 Files, paragraph 3: "When a stream is unbuffered, ... When a stream is fully buffered, ... When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. ..." In fact, the C Standard uses the exact phrase "line buffered" five times. So it's not a misnomer.
              – Andrew Henle
              Sep 6 at 14:41





              @ilkkachu The C standard does indeed use "line buffered". Per 7.21.3 Files, paragraph 3: "When a stream is unbuffered, ... When a stream is fully buffered, ... When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. ..." In fact, the C Standard uses the exact phrase "line buffered" five times. So it's not a misnomer.
              – Andrew Henle
              Sep 6 at 14:41





              1




              1




              Furthermore, the approach described here as "smart buffering", as I understand it, seems to be just what the C standard describes as "line buffering". Specifically, in addition to flushing the buffer at newlines, "When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when [...] input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment." So this is not a GNU or BSD quirk, but rather what the language calls for.
              – John Bollinger
              Sep 6 at 22:44





              Furthermore, the approach described here as "smart buffering", as I understand it, seems to be just what the C standard describes as "line buffering". Specifically, in addition to flushing the buffer at newlines, "When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when [...] input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment." So this is not a GNU or BSD quirk, but rather what the language calls for.
              – John Bollinger
              Sep 6 at 22:44











              up vote
              7
              down vote













              Use



              grep --line-buffered


              to make grep not buffer more than one line at a time.






              share|improve this answer
























                up vote
                7
                down vote













                Use



                grep --line-buffered


                to make grep not buffer more than one line at a time.






                share|improve this answer






















                  up vote
                  7
                  down vote










                  up vote
                  7
                  down vote









                  Use



                  grep --line-buffered


                  to make grep not buffer more than one line at a time.






                  share|improve this answer












                  Use



                  grep --line-buffered


                  to make grep not buffer more than one line at a time.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Sep 5 at 15:10









                  choroba

                  24.8k34168




                  24.8k34168



























                       

                      draft saved


                      draft discarded















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f467039%2fgrep-doesnt-output-until-eof-if-piped-through-cat%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Popular posts from this blog

                      How to check contact read email or not when send email to Individual?

                      Bahrain

                      Postfix configuration issue with fips on centos 7; mailgun relay