I am trying to implement a named-pipe communication solution between two processes in Bash.
The first process writes something to the named pipe:
send(){
echo 'something' > $NAMEDPIPE
}
And the second script is supposed to read the named pipe like this:
while true;do
if read line < $NAMEDPIPE;do
someCommands
fi
done
Note that the named pipe has been previously created using the traditional command
mkfifo $NAMEDPIPE
My problem is that the reader script is not always running so that if the writer script tries to write to the named-pipe it will stay blocked until a reader connects to the pipe.
I want to avoid this behavior, and a solution would be to trap a SIGPIPE signal. Indeed, according to man 7 signal is supposed to be sent when trying to write in a pipe with no reader. So I changed my red function by:
read(){
trap 'echo "SIGPIPE received"' SIGPIPE
echo 'something' > $NAMEDPIPE
}
But when I run the reader script, the script stays blocked, and "SIGPIPE received" does not get printed.
Am I mistaking on the signal mechanism or is there any better solution to my problem?
Here's a fun code I just made. Perhaps you can refer to this:
#!/bin/bash
shopt -s extglob
NAMEDPIPE=/var/run/sr-pipe
RECEIVER_PID_FILE=/var/run/sr-receiver-pid
function sender_start {
# Create named pipe.
if [[ -e $NAMEDPIPE ]]; then
echo "[Sender] Named pipe \"$NAMEDPIPE\" already exists."
else
echo "[Sender] Creating named pipe \"$NAMEDPIPE\"."
mkfifo "$NAMEDPIPE" || {
echo "Failed to create named pipe \"$NAMEDPIPE\"."
exit 1
}
fi
# Wait for receiver.
echo "[Sender] Waiting for receiver."
local PID
until [[ -e $RECEIVER_PID_FILE ]] \
&& read PID < "$RECEIVER_PID_FILE" \
&& [[ $PID == +([[:digit:]]) ]] \
&& kill -s 0 "$PID" &>/dev/null; do
sleep 1s
done
echo "[Sender] Receiver is [now] active."
# Send signal.
kill -s SIGPIPE "$PID"
# Send messages.
local SEND=''
echo "[Sender] Now sending messages."
while sleep 1s; do
SEND=$RANDOM
echo "[Sender] Sending $SEND."
echo "$SEND" >&4
done 4>"$NAMEDPIPE"
}
function receiver_start {
echo "$BASHPID" > "$RECEIVER_PID_FILE"
echo "[Receiver] Receiver is now active."
local QUIT=false RECEIVE=false
trap 'RECEIVE=true' SIGPIPE
trap 'QUIT=true' SIGINT SIGTERM SIGHUP
while [[ $QUIT == false ]]; do
if [[ $RECEIVE == true ]]; then
RECEIVE=false
echo "[Receiver] Now receiving messages."
while [[ $QUIT == false ]] && IFS= read -r -u 4 LINE; do
echo "[Receiver] Received $LINE."
done 4<"$NAMEDPIPE"
fi
sleep 1s
done
}
if [[ $1 == send ]]; then
sender_start
elif [[ $1 == receive ]]; then
receiver_start
fi
On one terminal I ran this:
# bash sender-receiver.sh send
[Sender] Named pipe "/var/run/sr-pipe" already exists.
[Sender] Waiting for receiver.
[Sender] Receiver is [now] active.
[Sender] Now sending messages.
[Sender] Sending 21524.
[Sender] Sending 1460.
[Sender] Sending 8352.
[Sender] Sending 4424.
...
And on another I got this (corrected):
# bash sender-receiver.sh receive
[Receiver] Receiver is now active.
[Receiver] Now receiving messages.
[Receiver] Received 21524.
[Receiver] Received 1460.
[Receiver] Received 8352.
[Receiver] Received 4424.
...
You probably can run sender on background and receiver on the foreground on the same terminal.