Bash – What’s the lifespan of a file descriptor

bashfile-descriptorsmemory management

As described here, redirections use open() to write to a file. There's an inner (?) file descriptor created in the shell, and then used when needed.

Is the inner descriptor created for the whole duration of the script or the shell lifetime? Is it destroyed after some time, a number of operations, etc?

I mean in particular file descriptors for the files that the shell itself opens for its builtins' operations. Is the descriptor created and the file opened for each operation? How long are they kept? Example:

#!/bin/bash
>>x echo something
...do many other things not related to the file x
>>x echo something more

Is the first descriptor instance kept until the second operation?

What about the shell I use in in a terminal? I sometimes keep one session open for days, maybe even weeks. Does it still keep the descriptors for all the files I operated on with shell built-ins?

Best Answer

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" }'
Related Question