What's the lifespan of a file descriptor?

They are closed when finished with. The shell will create 3 file descriptors 0,1,2 for each command that it runs. These are just numbers, the numbers are reused. The shell will close the files before re-using the descriptors.

File descriptors are also passed into other processes. And if you have a process in the background it will still have file descriptors.

The example uses 3>&1, this means make file descriptor 3 refer to the file that descriptor 1 currently refers to.


Briefly: A shell will almost certainly close file descriptors related to redirections immediately after the command completes.


Details: There's no explicit mention of closing the files opened through redirections in POSIX (as far as I can see). But not closing them immediately wouldn't be very useful.

The rules for the environment any commands are started in don't allow for passing extra file descriptors. The shell would need to take care to close any extra fd's it's saved when starting a command that shouldn't have them.

For the usual > filename output redirections, the file would in case need to be truncated when starting each command, even if the file descriptor was saved. And any saved file descriptor would point to a wrong file if the file concerned was renamed or removed in the meanwhile.

For example, this wouldn't behave correctly if the fd opened for the first echo was kept open and used as-is for the second:

echo foo >> x; mv x y; echo bar >> x

The usual fork+exec model used for starting external programs also makes it very easy to have the files automatically close when the command exits. The shell only needs to fork() first, and open any necessary files in the child process, before calling exec() to replace the child with the actual command. When the child process exits, any files opened by it are automatically closed.


In awk, though, the syntax for output redirection is similar to the shell, but any opened files are kept open until the script exits, unless explicitly closed. This will only open foo once, and will not truncate it in between the prints either:

awk 'BEGIN { print "a" > "foo"; print "b" > "foo" }'