Search code examples
bashshellio-redirection

How does code blocks `{...}` with I/O redirection work?


For example I have

sample.dat:

This is a 1st line.
This is a 2nd line.

when I type:

$ {read $line1; read $line2} < sample.dat

I got:

$ echo $line1
This is a 1st line.
$ echo $line2
This is a 2nd line.

So, I just thought that the above code may work in the same way as:

$ read $line1 < sample; read $line2 < sample.dat

but it turned out that it was not, the variables $line1 and $line2 are both "This is a 1st line.".

So, could anyone please explain me how code blocks with I/O redirection really work and how the statement {read $line1; read $line2} < sample.dat expand.


Solution

  • {..} < file runs a set of commands on the input stream opened. The descriptor opened to read from the stream is not opened every-time but only just once, even if there are multiple commands to be run.

    It is quite simple, once you understand the number of read calls you make at a given time. So basically doing < sample.dat redirects the content of the file to be made available in standard input or) file descriptor 0 (STDIN_FILENO)

    With a single call to read you request one line to be read from this input stream which happens when you do

    read line1 < sample.dat; read line2 < sample.dat
    

    Since the read commands are separated (using ;), each call opens the file once and reads only the first line available. The file descriptor opened by the first read command to read from standard input stream is closed once the first command is complete. The second call opens the standard input stream from the start offset again and does not advance to the second line.

    But with

    { read line1 ; read line2 ; } < sample.dat
    

    We open the file once and issue two calls to the read command. The first read gets the first line of input. Since the file descriptor is not closed yet, the second call to read advances the file pointer to seek to get the 2nd line of input from the file. Once both these commands complete, now the descriptor is closed.