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?

Ramesh
  • 39,297

2 Answers2

64

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,946
  • 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
  • 76,765
  • 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 <x, or x|y - it is a sort of redirection, but it redirects to a named pipe which you can use where a command would expect a filename. For instance, you can write diff <(ls foo) <(ls bar); the diff command thinks it is comparing two files, called something like /dev/fd/42 and /dev/fd/43, and is completely unaware that they are the piped output of some other command. – 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]<<REDIRECT in some shells. Where it differs is the shell's literal substitution of the fd link - /dev/fd/63 and etc and what it does - or doesnt do - with stdin. Do echo | readlink /dev/fd/0 and see for yourself. – 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 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 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