читать, а затем писать в программу c из сценария оболочки - PullRequest
4 голосов
/ 08 октября 2019

У меня есть короткая программа c, которая выводит 3 строки, затем читает из stdin, и я хотел бы использовать сценарий оболочки для взаимодействия с ним следующим образом:

  1. чтение вывода c, строка за строкойwhile read line; do ...; done <$out_
  2. сохранить вторую строку if [ "$count" == 2 ]; then input=$line; fi
  3. отправить сохраненную строку обратно в программу echo $input >$in_

Я использую именованные каналы в сценарии оболочки дляперенаправить вывод и ввод программы c:

./iotest >$out_ <$in_ &

но я не получаю ожидаемых результатов.

Проблема

После создания каналов out_ и in_ с mkfifo, у меня есть петля while read, но, похоже, это приводит к тупику. Ничего не читается, и сценарий оболочки застревает в команде чтения.

Я попытался добавить cat >$in_ & перед запуском iotest, как предлагалось здесь , чтобы открыть in_ для записина самом деле ничего не писать. Это разблокирует чтение, но не позволяет мне вводить в in_ (моя программа на c работает так, как будто я записал \ x00 в stdin, а команда echo $input >$in_ зависает).

Что япопробовал

Я прочитал здесь , который читает блоки, если нет записывающего, и без cat >$in_ & У меня iotest запись в out_ и read чтение из негоЯ пытаюсь перенаправить in_ на iotest, не записывая ничего с самого начала.

Но почему добавление команды cat приводит к сбою чтения программы на c, я не знаю. То же самое происходит, если я обменяю cat >$in_ & на while true; do :; done >$in_& или exec 3>$in_ & (exec 3>$in_, как предложено здесь , также зависает).

Код

Это мой код c:

$ cat iotest.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main (int argc, char* argv[])
{
    char A[9] = "";
    printf("hello. please send me the following line:\n");
    printf("input me\n");
    printf("now send me the line:\n");
    int ret = read(0,A,8);
    fprintf(stderr,"read returned %i\n",ret);
    if(ret != -1) {
        printf("You sent: %s\n", A);
        if (strcmp(A,"input me") == 0) {
            printf("correct!\n");
        } else {
            printf("wrong line.\n");
        }
    } else {
        printf("read failed.\n");
    }
    return 0;
}

и это сценарий оболочки, который я тестировал:

$ cat runiotest.sh 
#!/bin/bash

in_=/tmp/testpipein
out_=/tmp/testpipeout

mkfifo $in_
mkfifo $out_
count=0
input=""

./iotest >$out_ <$in_ &
while read line
do
    count=$((count+1))
    echo "line number $count:"
    echo $line
    if [ "$count" == 2 ]
    then
        input=$line
    fi
    if [ "$count" == 3 ]
    then
        echo "$input" >$in_
    fi
done < $out_

rm -f $in_
rm -f $out_

I 'мы проверили это на 32-битном Debian и 64-битном Ubuntu, скомпилировали с помощью gcc и выполнили сценарий оболочки с помощью bash.

Результаты

без добавления команды cat:

$ /bin/bash/ ./runiotest.sh
(hangs)

с добавлением cat >$in_ &:

$ /bin/bash ./runiotest.sh
read returned 0
line number 1:
hello. please send me the following line:
line number 2:
input me
line number 3:
now send me the line:
line number 4:
You sent:
line number 5:
wrong line.

Резюме

Поэтому мой вопрос: что не так с моим сценарием оболочки, и как я могу изменить его для чтения и записи вмоя программа c? Я не могу изменить сам код на c, но могу поиграться со скриптом оболочки.

Спасибо за любую помощь!

Ответы [ 2 ]

1 голос
/ 08 октября 2019

Рассмотрим:

./iotest >$out_ <$in_ &
while read line; do ...; done < $out_

Здесь подоболочка пытается открыть $ out_ для записи и $ in_ для чтения, и она даже не выполнит iotest, пока не будут открыты обе эти фиффы. Без добавленного cat подоболочка не сможет открыть $in_, пока не найдется какой-либо писатель, поэтому iotest никогда даже не начнет выполняться. Когда вы добавляете cat, подоболочка может открывать $in_, а основная оболочка действует как считыватель для $out_, поэтому подоболочка может открывать как fifo, так и выполнять iotest. Что касается поведения, которое вы видите, это ошибка в вашем iotest.c. Выведите значение, возвращаемое read (в stderr!), Включите объявление read и попробуйте использовать != -1 вместо > -1.

0 голосов
/ 09 октября 2019

Проблема была буферизация вывода программы c . Удаление буферизации с помощью stdbuf решило это:

cat >$in_ &
stdbuf -o0 ./iotest <$out_ >$in_ &

С этим изменением результат будет таким, как должен:

$ /bin/bash ./runiotest.sh 
line number 1
hello. please send me the following line:
line number 2
input me
line number 3
now send me the line:
read returned 8
line number 4
You sent: input me
line number 5
correct!

Просто добавить, что использование stdbuf не работает, еслиисполняемый файл имеет установленный бит setuid. В этом случае вы можете использовать unbuffer из ожидаемой утилиты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...