I want to read a file line by line using bash, tail and using a diferent file descriptor. all the guides use this method:

method 1:

echo 1111111 > z.txt
exec {newFD}< <(tail -f -c +0 "z.txt")

while IFS= read -r LINE0 <&${newFD}
    printf '%s' "$LINE0"

but this method works too:

method 2:

echo 1111111 > z.txt
while IFS= read -r LINE0 <&${newFD}
    printf '%s' "$LINE0"
done {newFD}< <(tail -f -c +0 "z.txt")

Is there any problem in using the second method?

and why I don't need exec in the second method? thank you.

{newFD} gave me a free file descriptor automatically:Feature available since bash 4.1+ (2009-12-31) {varname} style automatic file descriptor allocation


You don't. In both cases, you will get a new file descriptor allocated and stored in newFD, reading from the process substitution. There is no functional difference. The error behaviour may be subtly different between the two, but in this case it should not be noticeable.

Method 1 may be slightly more transparent about the lifetime of the fd (it is not scoped just to the while loop in either case), and puts the source closer to where it's used. I would probably prefer to write it that way for clarity's sake, but there is no practical difference. The file descriptor needs to be closed afterwards either way.

You can write this in whichever style you prefer to use, and both will be fine.

Note though that while read is not opening a file descriptor: the ordinary shell redirection operations that exist for any command are taking place, with either while or exec as the command. A while loop is considered a single compound command, and runs within the calling shell. All the usual things that can be attached to a command can go with a while loop too.

There is some special behaviour for redirections with exec when redirecting a standard IO stream (or another already-open FD): it will manipulate the current shell's environment permanently, and not only that of the subshell that runs the actual command. However, that doesn't apply to this situation with {newFD}< ....

When allocating a new FD dynamically like this the FD is always assigned in the parent, not the child, or else the variable would be useless. That means any command will work, and even

: <{newFD} <(...)

does the same thing as exec {newFD}< <(...) would.

| improve this answer | |
  • thank you. please when I use method 1 two times like that , while read ... & while read ... & I get the same FD newFD , does both while use the same FD really? or they are in a subshell and doesn't affect each other? – Badr Elmers Apr 24 '19 at 2:49
  • & puts the whole command into a subshell and the FD will be allocated in each one individually, so they are independent of each other even if they have the same value. – Michael Homer Apr 24 '19 at 2:59
  • thank you. yes. for new comers I made a mistake in my first comment. i said method 1 but it s method 2 where i get the same FD, method 1 gave me a diferent FD because exec is running in the same shell. – Badr Elmers Apr 24 '19 at 3:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.