Differences between revisions 8 and 15 (spanning 7 versions)
Revision 8 as of 2008-11-22 14:09:52
Size: 1173
Editor: localhost
Comment: converted to 1.6 markup
Revision 15 as of 2013-12-16 20:56:34
Size: 3250
Editor: exit1
Comment: Add ways to kill background writer in scripts
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
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.
Line 4: Line 5:
The basic use of NamedPipes is: The most basic use of NamedPipes is:
Line 11: Line 13:
This works, but `cat` dies after reading one line. (In fact, what happens is each time the named pipe is closed by the ''writer'', this signals an end of file condition for the ''reader''. So `cat`, the reader, terminates because it saw the end of its input.) 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.)
Line 16: Line 18:
Line 21: Line 24:
But if they can't be grouped for some reason, a better way is to assign a file descriptor to the pipe and write there: The use of `tail -f` instead of `cat` can be an option:

{{{
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. 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:
Line 37: Line 54:
Closing the fd causes the pipe's reader to receive the end of file indication. Closing the FD causes the pipe's reader to receive the end of file indication.

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:

{{{
mkfifo myfifo

# keep the fifo opened using a writer
cat > myfifo
}}}

Open a reader in another shell:

{{{
cat myfifo
}}}

Then use as many shell as you want to send data to the reader:

{{{
echo something > myfifo
# reader does not die
}}}

To end the reader interactively, go back to the 1st cat (writer) and send it an EOF using CTRL-D (or terminate it using CTRL-C).

To end the reader in a script, either save the PID of the 1st cat (writer) and kill it:

{{{
mkfifo myfifo
cat > myfifo & # this is the writer to keep the fifo open
myfifo_writer_pid=$! # save the PID

# continually read from the fifo as multiple other processes are writing to it
while read; do stuff; done < myfifo

# kill the fifo writer
kill "$myfifo_writer_pid"
}}}

Or create an extra fifo through which you can send EOF to the 1st cat:

{{{
mkfifo myfifo killfifo
cat killfifo > myfifo & # this is the writer to keep the fifo open

# continually read from the fifo as multiple other processes are writing to it
while read; do stuff; done < myfifo

# kill our background writer that keeps the fifo open by writing to it
# after this there are no more writers keeping myfifo open
printf '' > killfifo
}}}

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 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? 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

The use of tail -f instead of cat can be an option:

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. 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:

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.

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:

mkfifo myfifo

# keep the fifo opened using a writer
cat > myfifo

Open a reader in another shell:

cat myfifo

Then use as many shell as you want to send data to the reader:

echo something > myfifo
# reader does not die

To end the reader interactively, go back to the 1st cat (writer) and send it an EOF using CTRL-D (or terminate it using CTRL-C).

To end the reader in a script, either save the PID of the 1st cat (writer) and kill it:

mkfifo myfifo
cat > myfifo & # this is the writer to keep the fifo open
myfifo_writer_pid=$! # save the PID

# continually read from the fifo as multiple other processes are writing to it
while read; do stuff; done < myfifo

# kill the fifo writer
kill "$myfifo_writer_pid"

Or create an extra fifo through which you can send EOF to the 1st cat:

mkfifo myfifo killfifo
cat killfifo > myfifo & # this is the writer to keep the fifo open

# continually read from the fifo as multiple other processes are writing to it
while read; do stuff; done < myfifo

# kill our background writer that keeps the fifo open by writing to it
# after this there are no more writers keeping myfifo open
printf '' > killfifo

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