I have a short c programme that outputs 3 lines then reads from stdin, and I would like to use a shell script to interact with it as follows:
- read c output, line by line
while read line; do ...; done <$out_
- save 2nd line
if [ "$count" == 2 ]; then input=$line; fi
- send saved line back to programme
echo $input >$in_
I'm using named pipes in the shell script to redirect the output and input of the c programme:
./iotest >$out_ <$in_ &
but I'm not getting the results I'd expect.
Problem
After creating the pipes out_
and in_
with mkfifo
, I have a while read
loop but it seems to lead to a deadlock. Nothing is read, and the shell script gets stuck on the read command.
I tried adding cat >$in_ &
before launching iotest
, as proposed here, to open in_
for writing without actually writing anything. This unblocks the read but doesn't let me input to in_
(my c programme acts as if I'd written \x00 to stdin, and the echo $input >$in_
command hangs).
What I've tried
I've read here that read blocks if there is no writer, and wihtout cat >$in_ &
I have iotest
writing to out_
, and read
reading from it, I'm trying to redirect in_
to iotest
without writing anything to it from the start.
But why adding the cat command makes the c programme fail at reading, I don't know. The same happens if I exchange cat >$in_ &
with while true; do :; done >$in_&
or exec 3>$in_ &
(exec 3>$in_
, as proposed here, also hangs).
Code
This is my c code:
$ 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;
}
and this is the shell script I've tested:
$ 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've tested this on 32-bit debian and 64-bit ubuntu, compiling with gcc, and executing the shell script with bash.
Results
without the added cat command:
$ /bin/bash/ ./runiotest.sh
(hangs)
with added 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.
Summary
So my question is: What is wrong with my shell script, and how can I modify it to read then write to my c programme? I can't change the c code itself but can fiddle with the shell script.
Thank you for any help!