12

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?

0

2 Answers 2

6

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.

0
4

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

You must log in to answer this question.