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]
$ bash -c 'llfd () { echo "pid:$BASHPID" >&2; ls -l /proc/$BASHPID/fd/ >&2; }; x=3; eval "exec $x>/dev/null"; llfd; echo | llfd 3>&-' [not the same output; no fds pointing to /dev/null, as expected] When eval is run by the main shell and I want $x closed, I can just do 'eval "exec $x>&-"'. However, I cannot do that with eval runs in a subshell. In my script I needed $x open for other processes in that pipeline. On a different but related note, I hate having to do eval to manipulate an fd stored in a variable. Why doesn't 'llfd $x>&-' work, especially since 'llfd >&$x' works just fine... so by the time >& is handled, the variable substitutions seem to be done already. On Tue, Feb 12, 2013 at 2:13 AM, Pierre Gaston <pierre.gas...@gmail.com>wrote: > > > On Tue, Feb 12, 2013 at 1:54 AM, <matei.da...@gmail.com> wrote: > >> With the script below, I'd expect any fd pointing to /dev/null to be >> closed when the second llfd() is executed. Surprisingly, fd 3 is closed, >> but fd 10 is now open, pointing to /dev/null, as if eval copied it instead >> of closing it. Is this a bug? >> >> Thanks, >> M >> >> >> $ bash -c 'llfd () { ls -l /proc/$BASHPID/fd/; }; x=3; eval "exec >> $x>/dev/null"; llfd; eval "llfd $x>&-"' >> total 0 >> lrwx------ 1 matei matei 64 Feb 11 18:36 0 -> /dev/pts/2 >> lrwx------ 1 matei matei 64 Feb 11 18:36 1 -> /dev/pts/2 >> lrwx------ 1 matei matei 64 Feb 11 18:36 2 -> /dev/pts/2 >> l-wx------ 1 matei matei 64 Feb 11 18:36 3 -> /dev/null >> lr-x------ 1 matei matei 64 Feb 11 18:36 8 -> /proc/4520/auxv >> total 0 >> lrwx------ 1 matei matei 64 Feb 11 18:36 0 -> /dev/pts/2 >> lrwx------ 1 matei matei 64 Feb 11 18:36 1 -> /dev/pts/2 >> l-wx------ 1 matei matei 64 Feb 11 18:36 10 -> /dev/null >> lrwx------ 1 matei matei 64 Feb 11 18:36 2 -> /dev/pts/2 >> lr-x------ 1 matei matei 64 Feb 11 18:36 8 -> /proc/4520/auxv >> $ bash --version >> GNU bash, version 4.2.24(1)-release (x86_64-pc-linux-gnu) >> Copyright (C) 2011 Free Software Foundation, Inc. >> License GPLv3+: GNU GPL version 3 or later < >> http://gnu.org/licenses/gpl.html> >> >> This is free software; you are free to change and redistribute it. >> There is NO WARRANTY, to the extent permitted by law. >> $ >> > > Note that the same happens without using eval: > $ llfd 3>&- > total 0 > lrwx------ 1 pgas pgas 64 Feb 12 08:00 0 -> /dev/pts/0 > lrwx------ 1 pgas pgas 64 Feb 12 08:00 1 -> /dev/pts/0 > l-wx------ 1 pgas pgas 64 Feb 12 08:00 10 -> /dev/null > lrwx------ 1 pgas pgas 64 Feb 12 08:00 2 -> /dev/pts/0 > lrwx------ 1 pgas pgas 64 Feb 12 08:00 255 -> /dev/pts/0 > > But you need to consider what process you are examining, you use a > function and you examine the file descriptors of the process where this > function runs. > > A function runs in the same process as the parent shell, if it simply > closes 3 then there will be no more fd opened on >/dev/null in the parent > shell when the function returns > So what bash does is a little juggling with the file descriptors, moving 3 > temporarily to be able to restore it. > > > > > > > >