Another thing I tried was to open a fd with <() and use it later in a shell function. Surprisingly, the fd disappears (is closed) if the shell executes something unrelated in subshell:
$ bash -c 'xxx () { echo "got arg: $1" >&2; ls -gG /proc/$BASHPID/fd >&2; (echo "subprocess" >&2); ls -gG /proc/$BASHPID/fd >&2; cat $1; }; . lfd.sh; xxx <(echo "hi")' got arg: /dev/fd/63 total 0 lrwx------ 1 64 Feb 13 12:28 0 -> /dev/pts/9 lrwx------ 1 64 Feb 13 12:28 1 -> /dev/pts/9 lrwx------ 1 64 Feb 13 12:28 2 -> /dev/pts/9 lr-x------ 1 64 Feb 13 12:28 63 -> pipe:[5474849] lr-x------ 1 64 Feb 13 12:28 8 -> /proc/4520/auxv subprocess total 0 lrwx------ 1 64 Feb 13 12:28 0 -> /dev/pts/9 lrwx------ 1 64 Feb 13 12:28 1 -> /dev/pts/9 lrwx------ 1 64 Feb 13 12:28 2 -> /dev/pts/9 lr-x------ 1 64 Feb 13 12:28 8 -> /proc/4520/auxv cat: /dev/fd/63: No such file or directory $ Note how 63 is open before '(echo)' and closed after. Is this expected? On Wed, Feb 13, 2013 at 12:06 PM, Matei David <matei.da...@gmail.com> wrote: > Thank you for the explanation. > > > On Tue, Feb 12, 2013 at 8:32 PM, Chet Ramey <chet.ra...@gmail.com> wrote: > >> On 2/12/13 11:40 AM, Pierre Gaston wrote: >> > On Tue, Feb 12, 2013 at 6:07 PM, Matei David <matei.da...@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. >> >> Chet >> >> -- >> ``The lyf so short, the craft so long to lerne.'' - Chaucer >> ``Ars longa, vita brevis'' - Hippocrates >> Chet Ramey, ITS, CWRU c...@case.edu >> http://cnswww.cns.cwru.edu/~chet/ >> > >