Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write and read from a fifo from two different script

Tags:

bash

writer

fifo

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

like image 935
Ciccio Avatar asked Sep 17 '14 21:09

Ciccio


3 Answers

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.

like image 80
John1024 Avatar answered Nov 15 '22 20:11

John1024


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
like image 29
David C. Rankin Avatar answered Nov 15 '22 20:11

David C. Rankin


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

like image 38
Julian Avatar answered Nov 15 '22 20:11

Julian