Bash Redirection Using named pipes


Example

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 (&).