Sometimes you may want to output something by one program and input it into another program, but can't use a standard pipe.
ls -l | grep ".log"
You could simply write to a temporary file:
touch tempFile.txt
ls -l > tempFile.txt
grep ".log" < tempFile.txt
This works fine for most applications, however, nobody will know what tempFile
does and someone might remove it if it contains the output of ls -l
in that directory. This is where a named pipe comes into play:
mkfifo myPipe
ls -l > myPipe
grep ".log" < myPipe
myPipe
is technically a file (everything is in Linux), so let's do ls -l
in an empty directory that we just created a pipe in:
mkdir pipeFolder
cd pipeFolder
mkfifo myPipe
ls -l
The output is:
prw-r--r-- 1 root root 0 Jul 25 11:20 myPipe
Notice the first character in the permissions, it's listed as a pipe, not a file.
Now let's do something cool.
Open one terminal, and make note of the directory (or create one so that cleanup is easy), and make a pipe.
mkfifo myPipe
Now let's put something in the pipe.
echo "Hello from the other side" > myPipe
You'll notice this hangs, the other side of the pipe is still closed. Let's open up the other side of the pipe and let that stuff through.
Open another terminal and go to the directory that the pipe is in (or if you know it, prepend it to the pipe):
cat < myPipe
You'll notice that after hello from the other side
is output, the program in the first terminal finishes, as does that in the second terminal.
Now run the commands in reverse. Start with cat < myPipe
and then echo something into it. It still works, because a program will wait until something is put into the pipe before terminating, because it knows it has to get something.
Named pipes can be useful for moving information between terminals or between programs.
Pipes are small. Once full, the writer blocks until some reader reads the contents, so you need to either run the reader and writer in different terminals or run one or the other in the background:
ls -l /tmp > myPipe &
cat < myPipe
More examples using named pipes:
Example 1 - all commands on the same terminal / same shell
$ { ls -l && cat file3; } >mypipe &
$ cat <mypipe
# Output: Prints ls -l data and then prints file3 contents on screen
Example 2 - all commands on the same terminal / same shell
$ ls -l >mypipe &
$ cat file3 >mypipe &
$ cat <mypipe
#Output: This prints on screen the contents of mypipe.
Mind that first contents of file3
are displayed and then the ls -l
data is displayed (LIFO configuration).
Example 3 - all commands on the same terminal / same shell
$ { pipedata=$(<mypipe) && echo "$pipedata"; } &
$ ls >mypipe
# Output: Prints the output of ls directly on screen
Mind that the variable $pipedata
is not available for usage in the main terminal / main shell since the use of &
invokes a subshell and $pipedata
was only available in this subshell.
Example 4 - all commands on the same terminal / same shell
$ export pipedata
$ pipedata=$(<mypipe) &
$ ls -l *.sh >mypipe
$ echo "$pipedata"
#Output : Prints correctly the contents of mypipe
This prints correctly the value of $pipedata
variable in the main shell due to the export declaration of the variable. The main terminal/main shell is not hanging due to the invocation of a background shell (&
).