Is it possible that a program is already using it
No. You see, I/O redirection occurs before a program or a script is started.
Normally, when a program or script starts, only the standard descriptors (0/standard input, 1/standard output, and 2/standard error) are open. (They may refer to a terminal, device, file, or even a network socket; but they are expected to be open. Instead of "closing" one, we redirect an unwanted descriptor from/to
/dev/null, essentially "nowhere"/"nothing".)
Programs use descriptors via syscalls like
open which use a free descriptor. That is, they don't ask the kernel to open a file or socket to a specific descriptor, the kernel chooses the descriptor. So, the only case when a program uses an additional descriptor, is when it is expected to be already open when the program starts. There are some rare utility daemons like this -- in addition to the standard descriptors, they expect that if e.g. descriptor 3 is open when they start, it is connected to their management service (or something similar).
If a program decides to use a hard-coded descriptor (and the only reason it would, is because it forks and executes another program that expects that descriptor to be open; as I said, this is very rare), the already open descriptor gets closed when the program replaces it with whatever it is they use it for. (The kernel does the closing, by the way, when the program indicates they want to use a specific descriptor using e.g.
dup2() in POSIXy systems; the process does not need to care.)
Shell scripts (Bash and sh) use fixed descriptor numbers, so it is possible that a script uses a specific descriptor to do some input/output redirections.
However, when that happens, the previous redirections are simply ignored, and have no effect, because the scripts assume that descriptor was closed. (If a descriptor is open, and the script uses that descriptor for some internal stuff, the original descriptor is closed first -- by the kernel, and for the reasons mentioned in previous paragraph -- when the scripts redirects it. For any kind of data leakage to occur, the script would have to specially test if a descriptor is already open, and avoid redirecting it.)
Also note that Fortran I/O units or channels are not related to descriptors, even if both use a number for identification. So, even if a Fortran program uses unit 10, it does not mean it uses descriptor 10.
Is it safe to just use a fixed fd number for this?
Yes. POSIX says that a program can have at least 20 descriptors open, so any fixed number between 3 and 19 should work just fine.
The key point is documenting it well, preferably in a short comment at the beginning of the script (for scripts), or in the usage (
--help command-line option) and man page (for programs).
For scripts, you can assume that if a conflict arises (and if they do, it will be of the "script does not work at all because the pipe closes as soon as the program starts" variety, as detailed above), users can change the fixed descriptor number to suit their needs better. So, your task as the script writer is to plan ahead, and make that easier for those who come after. (A clear comment describing your intent and the overall design is enough; it is not necessary to make the descriptor number a variable, or describe every little action the script makes.)
For programs, it is a good idea to make it run-time configurable. For example, you could have your program/daemon use descriptor 3, if open, for special control protocol with a graphical user interface; but, using some command-line option, like '-c 5', use the named descriptor (or, with
-c /dev/name or
-c named-pipe or
-c :socketpath use the specified file, named pipe, or local domain socket). This way users can work around any conflicts with scripts with ease.