Differences between revisions 16 and 17
Revision 16 as of 2013-12-21 20:51:03
Size: 2397
Editor: geirha
Comment: Doesn't really work ...
Revision 17 as of 2014-03-27 07:57:10
Size: 3254
Editor: pgas
Comment: reorganize, expand a bit and provide a nicer alternative to cat >myfifo &
Deletions are marked like this. Additions are marked like this.
Line 2: Line 2:
Line 5: Line 6:
=== The problem ===
Line 12: Line 14:
Line 15: Line 16:
What if we want to write several times to the pipe without having to restart the reader?  We have to arrange for all our data to be sent without opening and closing the pipe multiple times. What if we want to write several times to the pipe without having to restart the reader?

=== Grouping the commands ===
We have to arrange for all our data to be sent without opening and closing the pipe multiple times.
Line 24: Line 28:
The use of `tail -f` instead of `cat` can be an option:
Line 26: Line 29:
{{{
tail -f myfifo &
=== Opening a file descriptor ===
Line 29: Line 31:
echo 'a' > myfifo
# Doesn't die
echo 'b' > myfifo
echo 'c' > myfifo
}}}

The problem here is that the process `tail` doesn't die, even if the named pipe is deleted. In a script this is not a problem as you can kill `tail` on exit. There is also the --pid option to tail that can prove useful in some cases.

But if they can't be grouped for some reason or if the use of` tail` is not an option, a better way is to assign a file descriptor to the pipe and write there:
It is basically the same idea as above, but using exec to have greater flexibility:
Line 53: Line 47:
Line 56: Line 49:
The file descriptor solution above works well to write to the fifo from a single shell, but it does not scale if many processes need to write to the fifo.
In this case, a solution is to keep the fifo opened by a writer:
This works well as long as all the writers are children of the same shell.


=== Using tail ===

The use of `tail -f` instead of `cat` can be an option, as tail will keep reading even if the pipe is closed:

{{{
tail -f myfifo &

echo 'a' > myfifo
# Doesn't die
echo 'b' > myfifo
echo 'c' > myfifo
}}}
The problem here is that the process `tail` doesn't die, even if the named pipe is deleted. In a script this is not a problem as you can kill `tail` on exit.

If your reader is a program that only reads from a file, you can still use tail with the help of process substitution:

{{{
myprogram <(tail -f myfifo) &
# Doesn't die
echo 'b' > myfifo
echo 'c' > myfifo
}}}

Here, tail will be closed when myprogram exits.

=== Using a guarding process ===

The pipe will be really closed when the last opened file descriptor will be closed, you can exploit this by keeping a file descriptor opened on a process doing nothing.

An elegant solution is to use a second pipe to control the guarding process:
Line 61: Line 85:
mkfifo guard
Line 62: Line 87:
# keep the fifo opened using a writer
cat > myfifo
}}}
# keep the fifo opened using a fake writer
read >myfifo < guard & #note the order is important!
Line 66: Line 90:
Open a reader in another shell: # if you do <guard first, it will be blocked
# and >myfifo will not be opened until guard is opened
Line 68: Line 93:
{{{ # start the reader
Line 72: Line 97:
Then use as many shell as you want to send data to the reader:
Now you can use writers in other unrelated process and the pipe will not be closed because of your process keeping it opened.
Line 79: Line 103:
To end the reader, go back to the 1st cat (writer) and send it an EOF using CTRL-D (or terminate it using CTRL-C). When you are finished and want to close the pipe, you just need to open and close the helper pipe to unblock the guarding processs:

{{{
: >guard
}}}


An alternative is to use a process doing nothing, killing it in the end:

{{{
mkfifo myfifo

while :;do sleep 10000 & wait;done >myfifo &
pid=$!

cat myfifo

kill $pid

}}}

How to write several times to a fifo without having to reopen it?

In the general case, you'll open a new FileDescriptor (FD) pointing to the fifo, and write through that. For simple cases, it may be possible to skip that step.

The problem

The most basic use of NamedPipes is:

mkfifo myfifo
cat < myfifo &
echo 'a' > myfifo

This works, but cat dies after reading one line. (In fact, what happens is when the named pipe is closed by all the writers, this signals an end of file condition for the reader. So cat, the reader, terminates because it saw the end of its input.)

What if we want to write several times to the pipe without having to restart the reader?

Grouping the commands

We have to arrange for all our data to be sent without opening and closing the pipe multiple times.

If the commands are consecutive, they can be grouped:

cat < myfifo &
{ echo 'a'; echo 'b'; echo 'c'; } > myfifo

Opening a file descriptor

It is basically the same idea as above, but using exec to have greater flexibility:

cat < myfifo &

# assigning fd 3 to the pipe
exec 3>myfifo

# writing to fd 3 instead of reopening the pipe
echo 'a' >&3
echo 'b' >&3
echo 'c' >&3

# closing the fd
exec 3>&-

Closing the FD causes the pipe's reader to receive the end of file indication.

This works well as long as all the writers are children of the same shell.

Using tail

The use of tail -f instead of cat can be an option, as tail will keep reading even if the pipe is closed:

tail -f myfifo &

echo 'a' > myfifo
# Doesn't die
echo 'b' > myfifo
echo 'c' > myfifo

The problem here is that the process tail doesn't die, even if the named pipe is deleted. In a script this is not a problem as you can kill tail on exit.

If your reader is a program that only reads from a file, you can still use tail with the help of process substitution:

myprogram <(tail -f myfifo) &
# Doesn't die
echo 'b' > myfifo
echo 'c' > myfifo

Here, tail will be closed when myprogram exits.

Using a guarding process

The pipe will be really closed when the last opened file descriptor will be closed, you can exploit this by keeping a file descriptor opened on a process doing nothing.

An elegant solution is to use a second pipe to control the guarding process:

mkfifo myfifo
mkfifo guard

# keep the fifo opened using a fake writer
read >myfifo < guard &  #note the order is important! 

# if you do <guard first, it will be blocked
# and >myfifo will not be opened until guard is opened

# start the reader
cat myfifo

Now you can use writers in other unrelated process and the pipe will not be closed because of your process keeping it opened.

echo something > myfifo
# reader does not die

When you are finished and want to close the pipe, you just need to open and close the helper pipe to unblock the guarding processs:

: >guard 

An alternative is to use a process doing nothing, killing it in the end:

mkfifo myfifo

while :;do sleep 10000 & wait;done >myfifo &
pid=$!

cat myfifo

kill $pid

BashFAQ/085 (last edited 2016-10-17 20:45:47 by 163-172-21-117)