37

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?

35

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.

  • 5
    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
  • 5
    There is no named pipe here. /dev/fd/63 is an anonymous pipe. – Gilles Sep 17 '14 at 21:06
  • 1
    @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 8 '16 at 19:35
  • 2
    @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 Feb 8 '16 at 20:00
  • 1
    Why is it 63, though? – K3---rnc Sep 5 '17 at 21:24
-6

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.

  • 1
    There is no redirection from a file here. <(…) is a process substitution. – Gilles 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
    @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
  • 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.