How to avoid echo closing FIFO named pipes? - Funny behavior of Unix FIFOs

前端 未结 6 1548
面向向阳花
面向向阳花 2020-12-04 08:10

I want to output some data to a pipe and have the other process do something to the data line by line. Here is a toy example:

mkfifo pipe
cat pipe&
cat &         


        
相关标签:
6条回答
  • 2020-12-04 08:43

    I enhanced the second version from the Jonathan Leffler's answer to support closing the pipe:

    dir=`mktemp -d /tmp/temp.XXX`
    keep_pipe_open=$dir/keep_pipe_open
    pipe=$dir/pipe
    
    mkfifo $pipe
    touch $keep_pipe_open
    
    # Read from pipe:
    cat < $pipe &
    
    # Keep the pipe open:
    while [ -f $keep_pipe_open ]; do sleep 1; done > $pipe &
    
    # Write to pipe:
    for i in {1..10}; do
      echo $i > $pipe
    done
    
    # close the pipe:
    rm $keep_pipe_open
    wait
    
    rm -rf $dir
    
    0 讨论(0)
  • 2020-12-04 08:49

    Put all the statements you want to output to the fifo in the same subshell:

    # Create pipe and start reader.
    mkfifo pipe
    cat pipe &
    # Write to pipe.
    (
      echo one
      echo two
    ) >pipe
    

    If you have some more complexity, you can open the pipe for writing:

    # Create pipe and start reader.
    mkfifo pipe
    cat pipe &
    # Open pipe for writing.
    exec 3>pipe
    echo one >&3
    echo two >&3
    # Close pipe.
    exec 3>&-
    
    0 讨论(0)
  • 2020-12-04 08:52

    When a FIFO is opened for reading, it blocks the calling process (normally). When a process opens the FIFO for writing, then the reader is unblocked. When the writer closes the FIFO, the reading process gets EOF (0 bytes to read), and there is nothing further that can be done except close the FIFO and reopen. Thus, you need to use a loop:

    mkfifo pipe
    (while cat pipe; do : Nothing; done &)
    echo "some data" > pipe
    echo "more data" > pipe
    

    An alternative is to keep some process with the FIFO open.

    mkfifo pipe
    sleep 10000 > pipe &
    cat pipe &
    echo "some data" > pipe
    echo "more data" > pipe
    
    0 讨论(0)
  • 2020-12-04 08:54

    You can solve this very easily by opening the read side of the pipe in read-write mode. The reader only gets an EOF once the last writer closes. So opening it in read-write makes sure there is always at least one writer.

    So change your second example to:

    mkfifo pipe
    cat <>pipe &
    echo "some data" >pipe
    
    0 讨论(0)
  • 2020-12-04 08:54

    As an alternative to the other solutions here, you can call cat in a loop as the input to your command:

    mkfifo pipe
    (while true ; do cat pipe ; done) | bash
    

    Now you can feed it commands one at a time and it won't close:

    echo "'echo hi'" > pipe
    echo "'echo bye'" > pipe
    

    You'll have to kill the process when you want it gone, of course. I think this is the most convenient solution since it lets you specify the non-exiting behavior as you create the process.

    0 讨论(0)
  • 2020-12-04 09:01

    Honestly, the best way I was able to get this to work was by using socat, which basically connections two sockets.

    mkfifo foo
    socat $PWD/foo /dev/tty
    

    Now in a new term, you can:

    echo "I am in your term!" > foo
    # also (surprisingly) this works
    clear > foo
    

    The downside is you need socat, which isn't a basic util everyone gets. The plus side is, I can't find something that doesn't work... I am able to print colors, tee to the fifo, clear the screen, etc. It is as if you slave the whole terminal.

    0 讨论(0)
提交回复
热议问题