This relates to issues #12542, #3948 and #3303 (and possibly others)
There is a general issue that fish cannot easily control what file descriptors get used and when (some external crates create their own fds for instance). This can create some issues when a script tries to use the same file descriptor value. and I believe it's also what prevent fish from implementing feature such as exec n>file.
So I think using the {var}>filename Bash feature would solve all those problems, especially if we make that the only way to use fds >2.
For reference, {var}>filename in Bash allows the shell to choose what file descriptor to use and stores the result in var. Then one can use it in other commands (e.g. cat <&$var).
fish could have such a feature, and possibly make that the only way to use file descriptors other than 0, 1 and 2 to avoid further issues (assuming only very few and/or niche apps require the shell to setup file descriptors at specific values).
Details:
- in place of
exec, implement a set --fd var filename (potentially, it could be a new set_fd builtin, but there is a lot of commonalities between set and would-be set_fd)
- possibly,
set --fd would setup a special kind of variable (i.e. different from the actual "string" type) for extra features/safety (i.e. prevent one from using a string where an fd is expected, see following points)
- alternatively, and if using
set_fd, the descriptors variables could be a completely separate set of variables, but I feel this would create another set of issues (e.g. how to refer to such variables since $var is for string?)
- deleting/reassigning the variable would close the fd
- this would allow using the variable scope (
set -[ugfl]) to auto-close the fd, without having the need for an explicit exec n>&- equivalent.
- this would reduce the risk of fd leaks (repeated assignment without explicit closing)
- increase safety (non-exported variables would close their fds before spawning a new process)
- an existing fd variable can only be assigned a new filename and other another fd variable (fd duplication)
- this eliminates the risk of assigning some random not-set-by-user fd (no
set --fd my_fd 3)
- the value of an fd could either be just the file descriptor value
$fd == 10, or for convenience/debug/readability be an array of [fd_value, filename] (i.e. $fd[1] == 10, $fd[2] == <filename>).
set --fd could support extra options, like --perm 0640, --mode [ro,wo,rw], --append, --no-clobber, ...
- implement
cmd {var}>filename for inline redirection
- this would be equivalent to
begin; set -lx var filename; cmd; end
- because of the equivalency,
echo $var {var}>finename should work (and print the fd value). So would /proc/self/fd/$var {var}</usr/bin/fish.
- implement default variables for
stdin/stdout/stderr for consistency, so one could do set --fd stdin my_file_to_read (i.e. exec 0<my_file_to_read)
- this would also work in combination with
set --fd var other_fd_var to duplicate the stdxxx descriptors (e.g. set --fd stderr stdout, aka 2>&1)
- the filename for the default stdin/stdout/stderr would be its dev path (
/dev/pts/x). Potentially, it could be - to be dev agnostic, but - only means current stdxxx, so its meaning/target changes when stdxxx changes
- deprecate the use of
n>file other than for 0,1 and 2.
Potential issues:
- the
begin; set -lx var filename; cmd; end equivalency:
this mean setting up the redirections before the rest of the command line can be expanded (for info, bash doesn't support it, and one needs to use a block to workaround it, i.e. { cmd $var; } {var}<filename)
- how to represent an "fd var" as an environment variable, i.e. for other apps?
- also, that representation needs to be reversible so that, for example,
fish > bash > fish should allow the child fish to recreate the parent fish fd vars (the fish > fish case is trivial if fish doesn't exec() itself after forking)
This relates to issues #12542, #3948 and #3303 (and possibly others)
There is a general issue that fish cannot easily control what file descriptors get used and when (some external crates create their own fds for instance). This can create some issues when a script tries to use the same file descriptor value. and I believe it's also what prevent fish from implementing feature such as
exec n>file.So I think using the
{var}>filenameBash feature would solve all those problems, especially if we make that the only way to use fds >2.For reference,
{var}>filenamein Bash allows the shell to choose what file descriptor to use and stores the result invar. Then one can use it in other commands (e.g.cat <&$var).fish could have such a feature, and possibly make that the only way to use file descriptors other than 0, 1 and 2 to avoid further issues (assuming only very few and/or niche apps require the shell to setup file descriptors at specific values).
Details:
exec, implement aset --fd var filename(potentially, it could be a newset_fdbuiltin, but there is a lot of commonalities betweensetand would-beset_fd)set --fdwould setup a special kind of variable (i.e. different from the actual "string" type) for extra features/safety (i.e. prevent one from using a string where an fd is expected, see following points)set_fd, the descriptors variables could be a completely separate set of variables, but I feel this would create another set of issues (e.g. how to refer to such variables since$varis for string?)set -[ugfl]) to auto-close the fd, without having the need for an explicitexec n>&-equivalent.set --fd my_fd 3)$fd == 10, or for convenience/debug/readability be an array of[fd_value, filename](i.e.$fd[1] == 10,$fd[2] == <filename>).set --fdcould support extra options, like--perm 0640,--mode [ro,wo,rw],--append,--no-clobber, ...cmd {var}>filenamefor inline redirectionbegin; set -lx var filename; cmd; endecho $var {var}>finenameshould work (and print the fd value). So would/proc/self/fd/$var {var}</usr/bin/fish.stdin/stdout/stderrfor consistency, so one could doset --fd stdin my_file_to_read(i.e.exec 0<my_file_to_read)set --fd var other_fd_varto duplicate the stdxxx descriptors (e.g.set --fd stderr stdout, aka2>&1)/dev/pts/x). Potentially, it could be-to bedevagnostic, but-only meanscurrent stdxxx, so its meaning/target changes when stdxxx changesn>fileother than for 0,1 and 2.Potential issues:
begin; set -lx var filename; cmd; endequivalency:this mean setting up the redirections before the rest of the command line can be expanded (for info, bash doesn't support it, and one needs to use a block to workaround it, i.e.
{ cmd $var; } {var}<filename)fish > bash > fishshould allow the child fish to recreate the parent fish fd vars (thefish > fishcase is trivial if fish doesn'texec()itself after forking)