从 shell 脚本读取然后写入 c 程序
read then write to c programme from shell script
我有一个简短的 c 程序,输出 3 行然后从标准输入读取,我想使用 shell 脚本与其交互,如下所示:
- 逐行读取 c 输出
while read line; do ...; done <$out_
- 保存第二行
if [ "$count" == 2 ]; then input=$line; fi
- 将保存的行发送回程序
echo $input >$in_
我在 shell 脚本中使用命名管道来重定向 c 程序的输出和输入:
./iotest >$out_ <$in_ &
但我没有得到预期的结果。
问题
在使用 mkfifo
创建管道 out_
和 in_
之后,我有一个 while read
循环,但它似乎会导致死锁。未读取任何内容,shell 脚本卡在读取命令上。
我尝试在启动 iotest
之前添加 cat >$in_ &
,正如 here 所提议的那样,以打开 in_
进行写入而不实际写入任何内容。这会解除对读取的阻塞,但不允许我输入 in_
(我的 c 程序就像我将 \x00 写入标准输入一样,并且 echo $input >$in_
命令挂起)。
我试过的
我已经读过 here 如果没有写入器则读取块,并且没有 cat >$in_ &
我有 iotest
写入 out_
,并且 read
从中读取,我试图将 in_
重定向到 iotest
而不是从一开始就向它写入任何内容。
但是为什么加了cat命令导致c程序读取失败,我就不知道了。如果我将 cat >$in_ &
与 while true; do :; done >$in_&
或 exec 3>$in_ &
交换(exec 3>$in_
,如提议的 here,也会挂起),也会发生同样的情况。
代码
这是我的 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;
}
这是我测试过的 shell 脚本:
$ 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_
我已经在 32 位 debian 和 64 位 ubuntu 上测试过,使用 gcc 编译,并使用 bash.
执行 shell 脚本
结果
没有添加 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.
总结
所以我的问题是:我的 shell 脚本有什么问题,我如何修改它以读取然后写入我的 c 程序?我无法更改 C 代码本身,但可以 fiddle 使用 shell 脚本。
感谢您的帮助!
考虑:
./iotest >$out_ <$in_ &
while read line; do ...; done < $out_
这里,subshell 尝试打开 $out_ 用于写入和 $in_ 用于读取,它甚至不会执行 iotest
直到这两个 fifos 都打开。如果没有您添加的 cat
,subshell 将无法打开 $in_
直到有一些编写器,所以 iotest
甚至永远不会开始执行。当你添加 cat
时,子 shell 可以打开 $in_
,而主 shell 充当 $out_
的 reader,所以 subshell 能够打开两个 fifos 并执行 iotest
。至于您看到的行为,这是 iotest.c 中的错误。打印 read
返回的值(到 stderr!),包括 read
的声明,并尝试使用 != -1
而不是 > -1
。
问题是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!
补充一下,如果可执行文件设置了 setuid 位,则使用 stdbuf 不起作用。在这种情况下,您可以使用 expect 实用程序中的 unbuffer
。
我有一个简短的 c 程序,输出 3 行然后从标准输入读取,我想使用 shell 脚本与其交互,如下所示:
- 逐行读取 c 输出
while read line; do ...; done <$out_
- 保存第二行
if [ "$count" == 2 ]; then input=$line; fi
- 将保存的行发送回程序
echo $input >$in_
我在 shell 脚本中使用命名管道来重定向 c 程序的输出和输入:
./iotest >$out_ <$in_ &
但我没有得到预期的结果。
问题
在使用 mkfifo
创建管道 out_
和 in_
之后,我有一个 while read
循环,但它似乎会导致死锁。未读取任何内容,shell 脚本卡在读取命令上。
我尝试在启动 iotest
之前添加 cat >$in_ &
,正如 here 所提议的那样,以打开 in_
进行写入而不实际写入任何内容。这会解除对读取的阻塞,但不允许我输入 in_
(我的 c 程序就像我将 \x00 写入标准输入一样,并且 echo $input >$in_
命令挂起)。
我试过的
我已经读过 here 如果没有写入器则读取块,并且没有 cat >$in_ &
我有 iotest
写入 out_
,并且 read
从中读取,我试图将 in_
重定向到 iotest
而不是从一开始就向它写入任何内容。
但是为什么加了cat命令导致c程序读取失败,我就不知道了。如果我将 cat >$in_ &
与 while true; do :; done >$in_&
或 exec 3>$in_ &
交换(exec 3>$in_
,如提议的 here,也会挂起),也会发生同样的情况。
代码
这是我的 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;
}
这是我测试过的 shell 脚本:
$ 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_
我已经在 32 位 debian 和 64 位 ubuntu 上测试过,使用 gcc 编译,并使用 bash.
执行 shell 脚本结果
没有添加 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.
总结
所以我的问题是:我的 shell 脚本有什么问题,我如何修改它以读取然后写入我的 c 程序?我无法更改 C 代码本身,但可以 fiddle 使用 shell 脚本。
感谢您的帮助!
考虑:
./iotest >$out_ <$in_ &
while read line; do ...; done < $out_
这里,subshell 尝试打开 $out_ 用于写入和 $in_ 用于读取,它甚至不会执行 iotest
直到这两个 fifos 都打开。如果没有您添加的 cat
,subshell 将无法打开 $in_
直到有一些编写器,所以 iotest
甚至永远不会开始执行。当你添加 cat
时,子 shell 可以打开 $in_
,而主 shell 充当 $out_
的 reader,所以 subshell 能够打开两个 fifos 并执行 iotest
。至于您看到的行为,这是 iotest.c 中的错误。打印 read
返回的值(到 stderr!),包括 read
的声明,并尝试使用 != -1
而不是 > -1
。
问题是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!
补充一下,如果可执行文件设置了 setuid 位,则使用 stdbuf 不起作用。在这种情况下,您可以使用 expect 实用程序中的 unbuffer
。