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.
{..} < 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.