57

I am trying to understand named pipes in the context of this particular example.

I type <(ls -l) in my terminal and get the output as, bash: /dev/fd/63: Permission denied.

If I type cat <(ls -l), I could see the directory contents. If I replace the cat with echo, I think I get the terminal name (or is it?).

echo <(ls -l) gives the output as /dev/fd/63.

Also, this example output is unclear to me.

ls -l <(echo "Whatever")
lr-x------ 1 root root 64 Sep 17 13:18 /dev/fd/63 -> pipe:[48078752]

However, if I give,ls -l <() it lists me the directory contents.

What is happening in case of the named pipe?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Ramesh
  • 38,687
  • 43
  • 140
  • 215

2 Answers2

62

When you do <(some_command), your shell executes the command inside the parentheses and replaces the whole thing with a file descriptor, that is connected to the command's stdout. So /dev/fd/63 is a pipe containing the output of your ls call.

When you do <(ls -l) you get a Permission denied error, because the whole line is replaced with the pipe, effectively trying to call /dev/fd/63 as a command, which is not executable.

In your second example, cat <(ls -l) becomes cat /dev/fd/63. As cat reads from the files given as parameters you get the content. echo on the other hand just outputs its parameters "as-is".

The last case you have, <() is simply replaced by nothing, as there is no command. But this is not consistent between shells, in zsh you still get a pipe (although empty).

Summary: <(command) lets you use the ouput of a command, where you would normally need a file.

Edit: as Gilles points out, this is not a named pipe, but an anonymous pipe. The main difference is, that it only exists, as long as the process is running, while a named pipe (created e.g. with mkfifo) will stay without processes attached to it.

crater2150
  • 3,836
  • 2
  • 22
  • 26
  • Thanks. I was reading about `mkfifo` which is when I got this question about named pipes. So, if I have understood correctly, `mkfifo` is something which does effectively `<(ls -l)` in one process and unless you issue `cat` in another process, it will remain blocked. Am I correct in my understanding? – Ramesh Sep 17 '14 at 19:09
  • 7
    `mkfifo` only creates the named pipe, without any content. So you need to write to it yourself (e.g. `mkfifo mypipe; ls > mypipe`). And yes, the writes to the pipe will block until some process reads from the pipe. – crater2150 Sep 17 '14 at 19:15
  • 12
    There is no named pipe here. `/dev/fd/63` is an anonymous pipe. – Gilles 'SO- stop being evil' Sep 17 '14 at 21:06
  • 2
    @crater2150, @Gilles /dev/fd/63 is indeed a named pipe. Check this with something like `file <(ls)`. The shell does create an anonymous pipe, but the file descriptor reflects as a named pipe in `/dev/fd`. If it were an anonymous pipe, it would not have a name and could not be opened by a command to which `/dev/fd/63` is passed. – r.v Feb 08 '16 at 19:35
  • 5
    @r.v It's still an anonymous pipe. The fact that there is a file name that refers to this anonymous pipe doesn't make it a named pipe: a named pipe is different, it exists somewhere on a filesystem, has permissions and ownership, etc. Entries of `/dev/fd` can refer to any file descriptor, even anonymous pipes and sockets, network sockets, shared memory segments, etc. – Gilles 'SO- stop being evil' Feb 08 '16 at 20:00
  • 4
    Why is it _63_, though? – K3---rnc Sep 05 '17 at 21:24
  • 4
    @K3---rnc The exact path that the pipe will have is not fixed and may differ between shells or even versions of the shell. So the 63 is just some non-reserved file descriptor, that bash seems to pick by a deterministic method. – crater2150 Sep 08 '17 at 15:49
-4

You misunderstand both the ls command and redirection. ls lists the files and directories given on the command line, I don't believe it accepts any input from stdin. Redirection > >> and < are ways to use a file to give input and collect output.

Thomas Dickey
  • 75,040
  • 9
  • 171
  • 268
rhubarbdog
  • 127
  • 2
  • 2
    There is no redirection from a file here. `<(…)` is a process substitution. – Gilles 'SO- stop being evil' Sep 17 '14 at 21:05
  • Process substitution is a synonym for redirection. The < symbol in bash, sh etc means squirt the screen output if the right hand command into the input of the left hand command, disconnecting the keyboard. i.e. stdout of right to stdin of left. Look at the last 2 exampless which evaluate to ls -l whatever and just ls -l as the redirection <() evaluates to nothing, so no output to squirt back to ls – rhubarbdog Sep 17 '14 at 22:10
  • `<(x)` is very different from ` – IMSoP Sep 17 '14 at 22:47
  • 1
    @IMSoP - as Gilles said - its not a named pipe - its an anonymous pipe. It is very much the same as `x|y` and nearly identical to `[num]< – mikeserv Sep 18 '14 at 05:12
  • I suggest that you read the bash manual and learn what process substitution is. Hint: search for “process substitution” or `<(`. – Gilles 'SO- stop being evil' Sep 18 '14 at 06:38
  • @mikeserv OK, but it's "named" in the sense that the `diff` command in my example is given names, and is unaware that a pipe is even in use. – IMSoP Sep 18 '14 at 08:49
  • 1
    @IMSoP - that's a `dev` link - a special file. you can do the same w/ any file descriptor on most linux systems - even typical `|pipes`, though i wont vouch for the behavior elsewhere. i get where youre coming from, but a named pipe is a separate thing unto itself - it is a file-system reference to an in-kernel pipe - a *regular* file-system reference, not a device file. – mikeserv Sep 18 '14 at 08:59
  • 1
    @mikeserv Interestingly, [the Bash manual mentions](https://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution) that it will work on systems without `/dev/fd/*` by creating a named pipe somewhere else. But I take the point that `/dev/fd/*` itself is a different mechanism than a named pipe proper. Incidentally, [Wikipedia's description](https://en.wikipedia.org/wiki/Process_substitution) could do with an explanation of this distinction. – IMSoP Sep 18 '14 at 17:40
  • @IMSoP - `bash` does do something weird there - and that also depends on how `bash` is compiled. It's like... I don't know... It sets up its own `/dev/stdin` links and etc - but I would have to believe the sysop's say would take priority there, right? I've never taken that train all the way. I don't like `bash` much. I think we're actually talking about different things now. Elsewhere in the manual it talks about `bash` setting up its own `/dev/udp/tcp/fd` links. Weird. Sorry about that. – mikeserv Sep 18 '14 at 19:10
  • 1
    @mikeserv According to other references I found, it's simpler than that: if `/dev/fd/*` isn't available, bash will make a named pipe in `/tmp`, and use that for process substitution instead. Doesn't seem so weird to me, just making the functionality available in as many environments as possible. – IMSoP Sep 18 '14 at 20:25