Why isn't this possible and what's the best way around it:
#!/bin/sh
desc=5; file=/etc/passwd
exec "$desc"<"$file" #the variable filedescriptor is the problem
I'd rather not eval.
Well, as to why it's not possible, you wouldn't want:
echo "$text">file
To stop working if $x happens to be a number.
You'd need to do:
eval 'exec '"$desc"'< "$file"'
For the shell to evaluate the exec 5< "$file" code. eval is OK as long as you're careful to only expand the things that need to be expanded (and that those expansions are safe) in its arguments (here by using strong quotes for everything but $desc). What would be wrong would be something like where the content of eval "exec $desc< $file"$file is given for the shell to evaluate as shell code.
With zsh, you can also use the sysopen builtin in the zsh/system module:
zmodload zsh/system
sysopen -u "$desc" -r -- "$file"
In: zsh, bash and ksh93
exec {desc}>&-
would work at closing the fd stored in $desc, but in
exec {desc}> file
The shell allocates a fd above 10 and assigns it to $desc. That can't be used to open file on the fd that was stored in $desc beforehand.
Note that exec >&"$desc" works because there's no ambiguity there... except in zsh and recent versions of bash that have a >& operator to redirect both stdout and stderr to a file (like in csh), and where echo something >& "$file" works only as long as $file is not numerical.
$x precisely to be a number? Or is there a typo?