1

I know that one can often trick command line utilities that expect a file to pipe into stdout out by passing /dev/stdout as the file name.

I'm wondering whether it's possible to make a tool pipe to a numbered file descriptor instead of stdout/stderr, just like I can do the following to pipe stderr instead of stdout:

command 2>&1 >/dev/null | grep 'something'

To make my question more concrete (minimal reproducible example): what do I need to replace /dev/stdout here so that the output ends up in file descriptor number 3 rather than stdout (I'm not asking a question about any particular tool, I want to know what string to use to pipe to fd 3 as I can pipe to fd 1 using /dev/stdout.

cp a /dev/stdout

Replace cp with a command that usually expects a file path.

Does the /dev/3 work? I'm looking for the analogue to /dev/stdout but for fd 3 instead of fd 1.

To rephrase the question in yet another way:

file descriptor 1 is to /dev/stdout 
what 
file descriptor 3 is to ???

What should I use here instead of ???

I've searched quite broadly but couldn't find anything.

Cornelius Roemer
  • 252
  • 3
  • 10
  • From paragraph 2 you seem to be asking a different question. May be you are mixing up a question and a proposal for an answer. Keep these two concepts separate. Ask one question, then show us what you have tried. – ctrl-alt-delor Jun 28 '22 at 22:23
  • There are several possible duplicates, e.g., this: [where is the location of stdin, stdout, stderr file descriptor in AIX(unix)](https://unix.stackexchange.com/questions/297019/where-is-the-location-of-stdin-stdout-stderr-file-descriptor-in-aixunix) – Thomas Dickey Jun 28 '22 at 23:13
  • @ctrl-alt-delor feel free to edit the question how you see fit - I can't figure out what you want me to do. – Cornelius Roemer Jun 29 '22 at 11:49
  • @ThomasDickey I don't think the question you linked as potential duplicate is a duplicate. Also the answers are very different. What are other possible duplicates? Maybe you can link to them so I can check? – Cornelius Roemer Jun 29 '22 at 11:51
  • Looking [this](https://unix.stackexchange.com/search?q=%2Fdev%2Ffd+%2Fdev%2Fstdin), you might see that this question isn't really unique (nor are the answers below). – Thomas Dickey Jun 29 '22 at 19:09
  • I can't edit as I don't know what you are asking. – ctrl-alt-delor Jun 30 '22 at 20:42
  • Is your second question (If so then it needs to be a separate question: multiple questions in one produce messy answers), “Is it possible to produce a tool that has another input/output as well as `stdin`, `stdout`, `stderr`?” – ctrl-alt-delor Jun 30 '22 at 20:46
  • @ctrl-alt-delor Thanks for trying to clarify the question. I'm sorry this was confusing. No, I did not intend to ask the question you suggested at all, in no way. I just used this as an example to make my question more concrete (sort of minimal reproducible example) but I guess this was confusing. I've edited the question, does it make more sense now? Simply speaking: _file descriptor 1 is to `/dev/stdout` what file descriptor 3 is to **???**_ – Cornelius Roemer Jul 14 '22 at 17:33

3 Answers3

3

On a number of systems (not all!), /dev/fd/ is a directory of filehandles. On Linux it's typically a link to /proc/self/fd, but on NetBSD9 (for example) it's an an actual directory.

So

% ( cat a > /dev/fd/9) 9>&1 >/dev/null | grep .
foo

However, cp seems to depend on the shell you use.

On CentOS7 with ksh93...

% cp a /dev/fd/9 9>&1 >/dev/null | cat
cp: cannot create regular file '/dev/fd/9': No such device or address

That's because /dev/fd/9 isn't a regular file. But with bash...

$ cp a /dev/fd/9 9>&1 >/dev/null | cat
foo

It worked!

We can see this is not guaranteed to exist on all platforms and is not portable, even between shells on the same platform!

Stephen Harris
  • 42,369
  • 5
  • 94
  • 123
  • 1
    That's because on Linux, ksh93 uses socketpairs instead of pipes for its `|` operator, and on Linux, /dev/fd/x are magic symlinks to the file opened on the corresponding fd rather than the special devices where open("/dev/fd/n") is like dup(n) on other systems. So it fails in ksh93 because you can't open() a socketpair while it doesn't in bash because you can open a pipe. In anycase, neither sockets nor pipes are *regular files*. – Stéphane Chazelas Jun 29 '22 at 06:24
  • 1
    @CorneliusRoemer, not on my mac. `/dev/` is a separate mount of `devfs`. E.g. running `exec 8> >(cat -n)` makes `/dev/fd/8` appear as a pipe; trying `echo blah > /dev/fd/123` fails with "Bad file descriptor" (assuming fd 123 isn't open); and a pipeline like `( cat hello.txt > /dev/fd/9) 9>&1 >/dev/null | cat -n` works to print the contents of `hello.txt` with line numbers. That's the same command is in the answer here, except I changed the filename and swapped `grep .` for `cat -n` to make it clear the the RHS of the pipe does something. Also see the `fd(4)` man page. – ilkkachu Jul 14 '22 at 20:21
  • Thanks @ilkkachu that's amazing, I just inspected the files there and could read some of them but never tried the commands. That's beautiful what you suggest. I'd appreciate that as an answer! Would be the accepted one. – Cornelius Roemer Jul 15 '22 at 14:28
1

Not on all systems as far as I know. But, on Debian and maybe all Gnu/Linuxes

/dev/stdout is a symlink to /proc/self/fd/1. If we look in the directory /proc/self/fd/, then we will find the other file descriptors. Note only the file descriptors that are in use will be in here. It will depend on the process.

ctrl-alt-delor
  • 27,473
  • 9
  • 58
  • 102
1

Try /proc/self/fd/«number»

You can actually access any processes files this way, by naming the process ID.

This is OS specific, and may not be there for all Unixes.

ctrl-alt-delor
  • 27,473
  • 9
  • 58
  • 102
David G.
  • 1,314
  • 1
  • 4
  • 15