What does the following script mean?
exec 4<&0 0</etc/XX/cfg
read line1
exec 0<&4
It redirects fd0 to fd4, and "/etc/XX/cfg" to fd0.
So why does read
still work, shouldn't that be empty?
What does the following script mean?
exec 4<&0 0</etc/XX/cfg
read line1
exec 0<&4
It redirects fd0 to fd4, and "/etc/XX/cfg" to fd0.
So why does read
still work, shouldn't that be empty?
It redirects stdin (FD0) to FD4, redirects from /etc/XX/cfg
to FD0, reads a line from FD0, and then moves FD4 back to FD0. In short, it saves, replaces, and restores stdin, while reading a line from a file in between.
read line1 < /etc/XX/cfg
would be so much easier, but it's impossible to tell if it's a valid replacement based only on the code shown.
dup2
syscall), so that reading from either descriptor will have the same effect. Of course, it then overwrites fd0, so you can think of it as "moving" the descriptor, if you like.
– ams
Apr 10 '12 at 10:56
To recast this in syscalls (using C):
exec 4<&0 0</etc/XX/cfg
/* Duplicate fd0 as fd4. */
dup2 (0, 4);
/* Open file on fd0.
"open" always uses lowest available descriptor, so we don't need to check it. */
close (0);
open ("/etc/XX/cfg", O_RDONLY);
exec 0<&4
/* Close fd0 and duplicate fd4 as fd0. */
dup2 (4, 0);
The way I read this - based on the bash manpage section on REDIRECTION - is that stdin
(fd0) is redirected into fd4, then input is taken from /etc/XX/cfg
into stdin
- which will end up on fd4.
read line1
should then take from fd4 which is then put back to fd0.
A demo might show my meaning a little better and answer "why" you might do this. By adding another line and putting it in a wrapper:
$ vim ./test.sh
#!/bin/bash
exec 4<&0 0</etc/XX/cfg
read line1 # reads from fd4
exec 0<&4
read line2 # reads from fd0
echo $line1
echo $line2
You can pipe or redirect stdin
via test.sh but also read in configuration by redirection, so in the code above I've pulled in values from the "config" (assumption on my part based on the filename - bad :) ), but I can process via stdin as well.
e.g:
$ ./test.sh < somefile
$ cat somefile | ./test.sh
Hopefully this explains it.