Неправильное чтение из именованного канала - PullRequest
3 голосов
/ 06 апреля 2020

У меня есть скрипт, который читает команды из именованного канала:

#! /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

Я запускаю его и тестирую командой:

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

И получаю странный вывод:

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

Каким-то образом скрипт не может прочитать всю строку, полученную из канала? Как это читать?

1 Ответ

3 голосов
/ 06 апреля 2020

Для этого должно быть запущено более одного считывателя именованного канала host-pipe.

Проверьте, работает ли второй экземпляр сценария в фоновом режиме или, возможно, в другом терминале. .

Пояснение

Вы обнаружите, что bash будет выдавать чтение из канала 1 байт за раз. Если вы используете Linux, вы можете strace свой сценарий. Вот выдержка:

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

Если у вас есть более одного процесса с этим шаблоном потребления, любой отдельный процесс увидит потерянные символы.

...