• Ksh problem with /dev/fd

    From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Tue Jul 28 09:27:31 2026
    From Newsgroup: comp.unix.shell

    Trying the following code with a Kornshell on Linux

    exec 4>&1
    echo hello | tee /dev/fd/4

    produces the error

    tee: /dev/fd/4: No such file or directory

    Above test code works fine with Bash or Dash, though.

    Any idea what's the problem with Ksh here? - Thanks.

    Janis

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Richard Harnden@richard.nospam@gmail.invalid to comp.unix.shell on Tue Jul 28 09:49:53 2026
    From Newsgroup: comp.unix.shell

    On 28/07/2026 08:27, Janis Papanagnou wrote:
    Trying the following code with a Kornshell on Linux

    -a exec 4>&1
    -a echo hello | tee /dev/fd/4

    produces the error

    -a tee: /dev/fd/4: No such file or directory

    Above test code works fine with Bash or Dash, though.

    Any idea what's the problem with Ksh here? - Thanks.

    Janis


    I'm not sure, but I think that /dev/fd/4 is really /proc/self/fd/4 and
    the pipe is a new process - so a different 'self'.

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.unix.shell on Tue Jul 28 09:25:03 2026
    From Newsgroup: comp.unix.shell

    In article <1149qfh$3t4ai$1@dont-email.me>,
    Richard Harnden <nospam.harnden@invalid.com> wrote:
    On 28/07/2026 08:27, Janis Papanagnou wrote:
    Trying the following code with a Kornshell on Linux

    exec 4>&1
    echo hello | tee /dev/fd/4

    produces the error

    tee: /dev/fd/4: No such file or directory

    Above test code works fine with Bash or Dash, though.

    Any idea what's the problem with Ksh here? - Thanks.

    Janis


    I'm not sure, but I think that /dev/fd/4 is really /proc/self/fd/4 and
    the pipe is a new process - so a different 'self'.

    Yes. The (obvious) workaround is to use /proc/$$/fd/4 instead (Yes, I just tested this under ksh).

    Of course, the interesting part of this is: Why the difference between the shells? You'd have to dig deep into the man pages (and/or the source code)
    to figure it out, but it seems that bash/dash runs the last command in a pipeline in the parent shell and all the others in subshells, but ksh does
    it the other way. I have no idea whether the standard(s) requires or
    prefers either option over the other.

    And yet, the "lastpipe" option (See: man bash) is off by default, which
    would seem to imply that, by default, the behavior described above does
    *not* apply to bash. Hmmm...
    --
    Politics is show business for ugly people.

    Sports is politics for stupid people.
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Tue Jul 28 11:31:24 2026
    From Newsgroup: comp.unix.shell

    On 2026-07-28 10:49, Richard Harnden wrote:
    On 28/07/2026 08:27, Janis Papanagnou wrote:
    Trying the following code with a Kornshell on Linux

    -a-a exec 4>&1
    -a-a echo hello | tee /dev/fd/4

    produces the error

    -a-a tee: /dev/fd/4: No such file or directory

    Above test code works fine with Bash or Dash, though.

    Any idea what's the problem with Ksh here? - Thanks.

    I'm not sure, but I think that /dev/fd/4 is really /proc/self/fd/4 and
    the pipe is a new process - so a different 'self'.

    On my system it's a soft-link: /dev/fd/ -> /proc/self/fd/
    (the link with root permissions, the latter with user permissions).

    If I understand your hint correctly then this should work:

    echo hello world |
    {
    exec 4>&1
    tee /dev/fd/4 # or alternatively, tee /proc/self/fd/4
    }

    alas - in Ksh - that all also doesn't work.

    (Usually Ksh also has less issues with pipes and processes, since
    the last pipe-process is running in the enclosing shell context
    and not in a sub-shell as in Bash.)

    And, as said, there's no issue with all that with Bash or Dash.

    Hmm..

    Janis

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From gazelle@gazelle@shell.xmission.com (Kenny McCormack) to comp.unix.shell on Tue Jul 28 09:39:53 2026
    From Newsgroup: comp.unix.shell

    In article <1149shf$3unmp$1@news.xmission.com>,
    Kenny McCormack <gazelle@shell.xmission.com> wrote:
    ...

    Yes. The (obvious) workaround is to use /proc/$$/fd/4 instead (Yes, I just >tested this under ksh).

    It seems the real answer is that ksh just doesn't pass down
    (whatever the opposite of "inherit" is - maybe bequeath...) fds to sub-processes. Observe:

    % ksh
    $ exec 4>&1
    $ ls -lsa /proc/$$/fd/
    total 0
    0 dr-x------ 2 gazelle users 5 Jul 28 03:28 .
    0 dr-xr-xr-x 9 gazelle users 0 Jul 28 03:26 ..
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 0 -> /dev/pts/2
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 1 -> /dev/pts/2
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 10 -> /home/users/g/gazelle/.sh_history
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 2 -> /dev/pts/2
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 4 -> /dev/pts/2
    $ ls -lsa /proc/self/fd/
    total 0
    0 dr-x------ 2 gazelle users 4 Jul 28 03:29 .
    0 dr-xr-xr-x 9 gazelle users 0 Jul 28 03:29 ..
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 0 -> /dev/pts/2
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 1 -> /dev/pts/2
    0 lrwx------ 1 gazelle users 64 Jul 28 03:29 2 -> /dev/pts/2
    0 lr-x------ 1 gazelle users 64 Jul 28 03:29 3 -> /proc/851981/fd
    $

    Note that fd4 is there for the shell itself ($$), but not for the 'ls'
    process (pid 851981).
    --
    The whole aim of practical politics is to keep the populace alarmed (and hence clamorous
    to be led to safety) by menacing it with an endless series of hobgoblins, all of them imaginary.

    H. L. Mencken
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Tue Jul 28 11:39:52 2026
    From Newsgroup: comp.unix.shell

    On 2026-07-28 11:25, Kenny McCormack wrote:
    In article <1149qfh$3t4ai$1@dont-email.me>,
    Richard Harnden <nospam.harnden@invalid.com> wrote:
    On 28/07/2026 08:27, Janis Papanagnou wrote:
    Trying the following code with a Kornshell on Linux

    exec 4>&1
    echo hello | tee /dev/fd/4

    produces the error

    tee: /dev/fd/4: No such file or directory

    Above test code works fine with Bash or Dash, though.

    Any idea what's the problem with Ksh here? - Thanks.

    Janis


    I'm not sure, but I think that /dev/fd/4 is really /proc/self/fd/4 and
    the pipe is a new process - so a different 'self'.

    Yes. The (obvious) workaround is to use /proc/$$/fd/4 instead (Yes, I just tested this under ksh).

    Indeed, that works. (With '$$', but not with 'self'.) - Thanks!


    Of course, the interesting part of this is: Why the difference between the shells? You'd have to dig deep into the man pages (and/or the source code) to figure it out, but it seems that bash/dash runs the last command in a pipeline in the parent shell and all the others in subshells, but ksh does
    it the other way.

    Erm, no. actually - in former times, don't know about now - Bash had
    all pipe processes executed in sub-shells. This was different from
    the original Ksh which had the last process not run in a sub-shell
    but in the "current" context.

    I have no idea whether the standard(s) requires or
    prefers either option over the other.

    Last time I looked POSIX did not mandate any of the two behaviors.
    That would actually be difficult given that there's at least two
    POSIX shells, Bash and Ksh, that behave differently in that respect.


    And yet, the "lastpipe" option (See: man bash) is off by default, which
    would seem to imply that, by default, the behavior described above does
    *not* apply to bash. Hmmm...

    Still puzzling what's "wrong" with Ksh.

    Janis

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Geoff Clare@geoff@clare.See-My-Signature.invalid to comp.unix.shell on Tue Jul 28 13:44:38 2026
    From Newsgroup: comp.unix.shell

    Janis Papanagnou wrote:

    Trying the following code with a Kornshell on Linux

    exec 4>&1
    echo hello | tee /dev/fd/4

    produces the error

    tee: /dev/fd/4: No such file or directory

    Above test code works fine with Bash or Dash, though.

    Any idea what's the problem with Ksh here? - Thanks.

    Ksh sets the close-on-exec flag for fds > 2 opened with exec. This is explicitly allowed by POSIX. You can force the fd to remain open by
    duping it to itself (although this is currently non-standard):

    $ ksh -c 'exec 4>&1; echo hello | tee /dev/fd/4'
    tee: /dev/fd/4: No such file or directory
    hello
    $ ksh -c 'exec 4>&1; echo hello | tee /dev/fd/4 4>&4'
    hello
    hello

    This came up last year in the Austin Group. It was a side-discussion
    that came out of another issue, but part of the resolution is that the
    above work-around will be added to the standard in POSIX.1-2024 TC1.

    See https://austingroupbugs.net/view.php?id=1913#c7300 which includes
    the following addition to the text for n>&word and n<&word:

    If word and n evaluate to the same open file descriptor, the
    operation is a no-op except in shells which set the close-on-exec
    flag for file descriptors greater than 2 opened using exec. In
    these shells, a redirection of this form can be used to clear the
    close-on-exec flag so that the file descriptor will remain open
    when executing a non-built-in utility.
    --
    Geoff Clare <netnews@gclare.org.uk>
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.unix.shell on Tue Jul 28 15:25:04 2026
    From Newsgroup: comp.unix.shell

    On 2026-07-28 14:44, Geoff Clare wrote:
    Janis Papanagnou wrote:

    Trying the following code with a Kornshell on Linux

    exec 4>&1
    echo hello | tee /dev/fd/4

    produces the error

    tee: /dev/fd/4: No such file or directory

    Above test code works fine with Bash or Dash, though.

    Any idea what's the problem with Ksh here? - Thanks.

    Ksh sets the close-on-exec flag for fds > 2 opened with exec. This is explicitly allowed by POSIX. You can force the fd to remain open by
    duping it to itself (although this is currently non-standard):

    $ ksh -c 'exec 4>&1; echo hello | tee /dev/fd/4'
    tee: /dev/fd/4: No such file or directory
    hello
    $ ksh -c 'exec 4>&1; echo hello | tee /dev/fd/4 4>&4'
    hello
    hello

    Oh! - This is... - somewhat strange.

    This came up last year in the Austin Group. It was a side-discussion
    that came out of another issue, but part of the resolution is that the
    above work-around will be added to the standard in POSIX.1-2024 TC1.

    Okaaay.


    See https://austingroupbugs.net/view.php?id=1913#c7300 which includes
    the following addition to the text for n>&word and n<&word:

    If word and n evaluate to the same open file descriptor, the
    operation is a no-op except in shells which set the close-on-exec
    flag for file descriptors greater than 2 opened using exec. In
    these shells, a redirection of this form can be used to clear the
    close-on-exec flag so that the file descriptor will remain open
    when executing a non-built-in utility.

    Thanks for the insights!

    Janis

    --- Synchronet 3.22a-Linux NewsLink 1.2