[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: fd leak with {fd}>

From: Dan Douglas
Subject: Re: fd leak with {fd}>
Date: Sat, 01 Dec 2012 00:00:10 -0600
User-agent: KMail/4.8.3 (Linux/3.4.6-pf+; KDE/4.8.3; x86_64; ; )

On Monday, November 26, 2012 11:57:33 AM Chet Ramey wrote:
> On 11/26/12 8:41 AM, Pierre Gaston wrote:
> > On Mon, Nov 26, 2012 at 3:37 PM, Chet Ramey <address@hidden
> > <mailto:address@hidden>> wrote:
> > 
> > On 11/23/12 2:04 AM, Pierre Gaston wrote:
> > > It seems rather counter intuitive that the fd is not closed after 
> > > the block.
> > > With the normal redirection the fd is only available inside the block
> > >
> > > $ { : ;} 3>&1;echo bar >&3
> > > -bash: 3: Bad file descriptor
> > >
> > > if 3 is closed why should I expect {fd} to be still open?
> > 
> > Because that's part of the reason to have {x}: so the user can handle the
> > disposition of the file descriptor himself.
> > 
> > . 
> > I don't see any difference between 3> and {x}> except that the later free
> > me from the hassle of avoid conflicting fd
> That's not really an issue.  Bash goes to great effort to allow users to
> specify fds it is already using internally.
> The user/shell programmer getting a handle to the fd is one benefit.  The
> ability to use those named fds in operators that don't allow words (e.g.
> variable expansions) to replace the explicit file descriptor number is
> another.
> David Korn beat all of us in implementing this feature (we first began
> discussing it in 2005).  I should ask him if he has additional insight.
> Chet

I believe one of the motivations for named FDs other than automatic FD 
allocation, and the reason they remain open, was probably to deal with 
organizing and grouping coprocesses so that you could follow the variable 
names rather than the FDs directly due to the somewhat awkward way they are 

ksh, mksh, and zsh have almost the same system (except the Zsh "coproc" 
pipeline modifier replaces Ksh's "|&" list operator) in which you start with 
an "anonymous coproc" that can only be accessed indirectly through "read -p" 
and "print -p", until moving the current coproc to a named FD with the special 
"&p" redirects. After that, and you have a handle on the real FD, you can open 
a new anonymous coproc and begin interacting with the others through "read -u" 
and "print -u" instead. Basically:

coproc { ...; }; read -ru "${COPROC}"

Everybody else:
{ ...; } |& { read -ru "$COPROC"; } {COPROC[0]}<&p {COPROC[1]}>&p

I suppose the idea was that you could have collections of coprocs organized 
into arrays held open until you're finished with them. Bash does it without 
adding all that extra syntax, so the FD assignment feature is less important, 
with the downside being there are a bunch of incompatible conflicts like the 
"|&" pipe and "read -p" (unnecessary features IMO, but not a big deal).

One potential gotcha in Bash is that RETURN traps execute while exposed to the 
fds that were redirected during the call to the function, not to the 
definition. I don't know if that's intentional or whether most people are 
aware that both sets of redirects are active until returning even if a 
redirect to the definition hides another made to the call. Since you can only 
access local variables from a RETURN trap, but the visible FDs are a 
combination of redirects held open from a execs or named FD assignments, plus 
redirects to the function call, it could be easy to be surprised if relying 
upon RETURN to close the right FD especially if variable names from different 
scopes conflict.

$ bash -s <<\EOF
f() {
    trap 'trap - RETURN; cat "/dev/fd/$x" -; exec {x}<&-' RETURN
    local x
    : <<<inner {x}<&0
    cat "/dev/fd/$x" -
} <<<middle
f <<<outer

Dan Douglas

reply via email to

[Prev in Thread] Current Thread [Next in Thread]