Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong read from a named pipe

I have a script which reads commands from a named pipe:

#! /usr/bin/env bash
host_pipe="host-pipe"

#pipe for executing commands
[ -p "$host_pipe" ] || mkfifo -m 0600 "$host_pipe" || exit 1 
chmod o+w "$host_pipe"

set -o pipefail

while :; do
    if read -r cmd <$host_pipe; then
        if [ "$cmd" ]; then
            printf 'Running: %s \n' "$cmd"
        fi
    fi
done

I run it and test with command:

bash -c "echo 'abcdef' > host-pipe"
bash -c "echo 'abcdef' > host-pipe"
bash -c "echo 'abcdef' > host-pipe"
bash -c "echo 'abcdef' > host-pipe"

And get the strange output:

Running: abcdf 
Running: abcdef 
Running: abcde 
Running: abcdf 
Running: ace

Somehow the script can't read all the string it get from the pipe? How to read it?

like image 822
denn Avatar asked Sep 07 '25 21:09

denn


1 Answers

You must have more than one reader of the named pipe host-pipe running for this to happen.

Check to see if you have a second instance of the script running in the background or possibly in another terminal.

Explanation

You will find that bash will issue reads from the pipe 1 byte at a time. If you are on Linux, you can strace your script. Here is an excerpt:

open("host-pipe", O_RDONLY|O_LARGEFILE) = 3
fcntl64(0, F_GETFD)                     = 0
fcntl64(0, F_DUPFD, 10)                 = 10
fcntl64(0, F_GETFD)                     = 0
fcntl64(10, F_SETFD, FD_CLOEXEC)        = 0
dup2(3, 0)                              = 0
close(3)                                = 0
ioctl(0, TCGETS, 0xbf99bfec)            = -1 ENOTTY (Inappropriate ioctl for device)
_llseek(0, 0, 0xbf99c068, SEEK_CUR)     = -1 ESPIPE (Illegal seek)
read(0, "a", 1)                         = 1
read(0, "b", 1)                         = 1
read(0, "c", 1)                         = 1
read(0, "d", 1)                         = 1
read(0, "e", 1)                         = 1
read(0, "f", 1)                         = 1
read(0, "\n", 1)                        = 1
dup2(10, 0)                             = 0
fcntl64(10, F_GETFD)                    = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0

Once you have more than one process with this consumption pattern, any single process will see lost characters.

like image 185
rtx13 Avatar answered Sep 09 '25 17:09

rtx13