[Top][All Lists]

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

Re: eval doesn't close file descriptor?

From: Chet Ramey
Subject: Re: eval doesn't close file descriptor?
Date: Tue, 12 Feb 2013 20:32:50 -0500
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/17.0 Thunderbird/17.0

On 2/12/13 11:40 AM, Pierre Gaston wrote:
> On Tue, Feb 12, 2013 at 6:07 PM, Matei David <matei.david@gmail.com> wrote:
>> Ok, but I see the same behaviour when eval runs in a subshell:
>> $ bash -c 'llfd () { echo "pid:$BASHPID" >&2; ls -l /proc/$BASHPID/fd/
>>> &2; }; x=3; eval "exec $x>/dev/null"; llfd; echo | eval "llfd $x>&-"'
>> [same output, fd 10 open, pointing to /dev/null, even though it's a
>> subshell]
> eval runs in a subshell, but it's the same thing inside this subshell.
> eg you could have: echo | { eval "llfd "$x>&-"; echo blah >&3; }
> Bash could optimize this once it realizes there's only one command, but
> it's probably not that simple to implement.

The basic flow is like this for any builtin command or shell function that
has a redirection (let's choose 'llfd 3>&-').

1.  The redirection is performed in the current shell, noting that it
    should be `undoable'.  That takes three steps:

1a. In this case, since fd 3 is in use, we dup it (to fd 10) and mark fd
    10 as close-on-exec.  We add a separate redirection to an internal
    list  that basically says "close fd 10".  Then we add another
    redirection to the front of the same internal list that says "dup fd
    10 back to fd 3".  Let's call this list "redirection_undo_list".  We
    will use it to restore the original state after the builtin or
    function completes.

1b. Take the first redirection from step 1a and add it to a separate
    internal list that will clean up internal redirections in the case
    that exec causes the redirections to be preserved, and not undone.
    Let's call this list "exec_redirection_undo_list".

1c. Perform the redirection.  Here, that means close fd 3.

[perform step 1 for each redirection associated with the command]

2.  If we're running the exec builtin, throw away the list from 1a.  If
    we're not running the exec builtin, throw away the list from 1b.  Save
    a handle to the list we didn't discard.

3.  Run the function or builtin.

4.  Take the list saved in step 2 and perform the redirections to
    restore the previous state.  Here, that means we dup fd 10 back to fd
    3, then close fd 10.

If you look at the steps, it should be clear why fd 10 is still open when
llfd executes.

Bash `cheats' when running builtins or shell functions in pipelines or
other subshells.  It knows it's already going to be in a child process
when it performs the redirections, so it doesn't bother setting up the
structures to undo them.


``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRU    chet@case.edu    http://cnswww.cns.cwru.edu/~chet/

reply via email to

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