Write and read from a fifo from two different script
Asked Answered
B

3

14

I have two bash script. One script write in a fifo. The second one read from the fifo, but AFTER the first one end to write.

But something does not work. I do not understand where the problem is. Here the code.

The first script is (the writer):

#!/bin/bash

fifo_name="myfifo";

# Se non esiste, crea la fifo;
[ -p $fifo_name ] || mkfifo $fifo_name;

exec 3<> $fifo_name;

echo "foo" > $fifo_name;
echo "bar" > $fifo_name;

The second script is (the reader):

#!/bin/bash

fifo_name="myfifo";

while true
do
    if read line <$fifo_name; then
       # if [[ "$line" == 'ar' ]]; then
        #    break
        #fi
        echo $line
    fi
done

Can anyone help me please? Thank you

Blackington answered 17/9, 2014 at 21:46 Comment(2)
What do you mean by "Something does not work"?Beaubeauchamp
No script give me any error. But when i run the second script nothing is printed on the screen. So i do not understand if I am wrong when I write in the fifo or when I read from the fifoBlackington
F
13

Replace the second script with:

#!/bin/bash    
fifo_name="myfifo"
while true
do
    if read line; then
        echo $line
    fi
done <"$fifo_name"

This opens the fifo only once and reads every line from it.

Faerie answered 17/9, 2014 at 22:9 Comment(6)
Doe not work to me :( When I run the second script nothing happen and also the script does not terminate :( I must press CTRL + CBlackington
@Ciccio Yes, the script does not terminate because it is waiting for something to read from the fifo. While it is waiting, run the other script which writes to the fifo.Faerie
@Ciccio Also, the first script does not terminate until some process has read from the fifo. When the second script finishes reading what the first script wrote, the first script will terminate. The second script, because of the while true loop, continues waiting for more input.Faerie
Thank you John but perhaps it is not what I really need. I try to explain better. I need a script that create a fifo, write in two numbers and close fifo. I need then a secon script that open the fifo, read what has been written, print out the screen what it has been read and in the end terminate.Blackington
@Ciccio From man fifo: "The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also." Your application sounds better suited to using a normal file for message passing.Faerie
MM.. I understand... so I think I have to change the approach.. I must thinkBlackington
K
3

The problem with your setup is that you have fifo creation in the wrong script if you wish to control fifo access to time when the reader is actually running. In order to correct the problem you will need to do something like this:

reader: fifo_read.sh

#!/bin/bash

fifo_name="/tmp/myfifo"                         # fifo name

trap "rm -f $fifo_name" EXIT                    # set trap to rm fifo_name at exit

[ -p "$fifo_name" ] || mkfifo "$fifo_name"      # if fifo not found, create

exec 3< $fifo_name                              # redirect fifo_name to fd 3
                                                # (not required, but makes read clearer)
while :; do
    if read -r -u 3 line; then                  # read line from fifo_name
        if [ "$line" = 'quit' ]; then           # if line is quit, quit
            printf "%s: 'quit' command received\n" "$fifo_name"
            break
        fi
        printf "%s: %s\n" "$fifo_name" "$line"  # print line read
    fi
done

exec 3<&-                                       # reset fd 3 redirection

exit 0

writer: fifo_write.sh

#!/bin/bash

fifo_name="/tmp/myfifo"

# Se non esiste, exit :);
[ -p "$fifo_name" ] || {
    printf "\n Error fifo '%s' not found.\n\n" "$fifo_name"
    exit 1
}

[ -n "$1" ] && 
    printf "%s\n" "$1" > "$fifo_name" || 
    printf "pid: '%s' writing to fifo\n" "$$" > "$fifo_name"

exit 0

operation: (start reader in 1st terminal)

$ ./fifo_read.sh                         # you can background with & at end

(launch writer in second terminal)

$ ./fifo_write.sh "message from writer"  # second terminal
$ ./fifo_write.sh
$ ./fifo_write.sh quit

output in 1st terminal:

$ ./fifo_read.sh
/tmp/myfifo: message from writer
/tmp/myfifo: pid: '28698' writing to fifo
/tmp/myfifo: 'quit' command received
Krasner answered 18/9, 2014 at 4:55 Comment(2)
+1 You address the issue at hand, but as a note: Would not read -r line<$fifo_name be better? As it is now the reader script is going to enter a CPU intensive loop after first message. The same goes for the approach given by John1024.Chatham
Thanks. As noted in the comment, the persistent redirection to fd3 is not necessary, the purpose was just to keep the script logic clean a make it apparent that the fifo was being redirected and used to feed read. (it also gave the opportunity to show reading from a custom file descriptor -- which is necessary if reading from multiple fds in a single loop (e.g. fd3 & stdin). I don't see any reason your approach would not work equally as well offhand. Give it a shot.Krasner
J
1

The following script should do the job:

#!/bin/bash

FIFO="/tmp/fifo"

if [ ! -e "$FIFO" ]; then
        mkfifo "$FIFO"
fi

for script in "$@"; do
        echo $script > $FIFO &
done

while read script; do
        /bin/bash -c $script
done < $FIFO

Given two script a.sh and b.sh where both scripts pass "a" and "b" to stdout, respectively, one will get the following result (given that the script above is called test.sh):

./test.sh /tmp/a.sh /tmp/b.sh
a
b

Best, Julian

Janitor answered 14/7, 2016 at 8:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.