如何使用read()系统调用将用户输入脚本编写到程序中?

时间:2017-04-09 20:09:55

标签: c system-calls buffering

我在Linux环境中使用了几个二进制文件,并且我试图编写用户输入的脚本。例如,使用第一个程序prog1.c:

void get_input() {

    int i;
    char buffer[32];

    i = 0;

    while (i < 3) {
        memset(buffer, 0, 32);
        printf("Enter input: ");
        fgets(buffer, 31, stdin);
        printf("Your input: %s\n", buffer);
        i++;
    }
}

我可以运行prog1并直接从控制台输入输入,或者我可以编写输入脚本并将其输入程序。

直接从控制台输入输入:

# ./prog1
Enter input: Stuff1
Your input: Stuff1

Enter input: Stuff2
Your input: Stuff2

Enter input: Stuff3
Your input: Stuff3

#

脚本输入:

# perl -e 'print "Stuff1\n" . "Stuff2\n" . "Stuff3\n"' | ./prog1
Enter input: Your input: Stuff1

Enter input: Your input: Stuff2

Enter input: Your input: Stuff3

#

虽然输出的格式有点乱,但程序仍会显示预期的输出。

我的问题在于第二个二进制文件prog2.c:

void get_input() {

    int i;
    char buffer[32];

    i = 0;
    while (i < 3) {
        memset(buffer, 0, 32);
        printf("Enter input: ");
        read(0, buffer, 31);
        printf("Your input: %s\n", buffer);
        i++;
    }
}

当我可以直接从控制台输入我的输入时:

# ./prog2
Stuff1
Enter input: Your input: Stuff1

Stuff2
Enter input: Your input: Stuff2

Stuff3
Enter input: Your input: Stuff3

#

输入输入的提示不仅在我输入输入后才显示,但我甚至无法编写输入脚本:

# perl -e 'print "Stuff1\n" . "Stuff2\n" . "Stuff3\n"' | ./prog2
Enter input: Your input: Stuff1
Stuff2
Stuff3

Enter input: Your input:
Enter input: Your input:
#

我对fgets()read()之间的差异做了一些研究并发现:

  1. fgets()是C函数,而read()是系统调用。
  2. fgets()读取输入,直到遇到换行符或EOF,而换行不会对read()系统调用产生相同的影响。
  3. read()采用某种fgets()没有的缓冲机制。
  4. 我认为第2点和第3点与手头的问题最相关,但他们并没有暗示如何解决我的问题。

    我需要提供这些程序的用户输入涉及不可打印的十六进制字节,这就是为什么直接从控制台输入这样的输入是不够的。我也无法将源代码修改为二进制文件,因此没有解决办法只使用fgets()来收集输入。

    我的问题是,是否有任何方法可以将输入提供给prog2,以便我获得与prog1相同的行为。

    谢谢。

3 个答案:

答案 0 :(得分:3)

read(2)不会缓冲,但来自fgets/printf/etc的{​​{1}}可以提高性能。

如果您想阅读行,请坚持使用<stdio.h>。但是,如果要读取不可打印数据块(即二进制),请使用fgets。无论如何,请检查返回值。

答案 1 :(得分:1)

在阅读“二进制文件”时文件(可以包含NUL字节等)使用&#39; read()&#39;或者&#39; fread()&#39;

阅读文字文件时,请使用&#39; fgets()&#39;

答案 2 :(得分:0)

我找到了解决此问题的方法。我仍然无法按照我想要的方式与二进制文件进行交互 - 从控制台编写我的输入脚本 - 但我找到了一种以编程方式执行此操作的方法。

我正在使用一个Python库套件作为subprocess模块的包装器,但您可以自己编写:

p = subprocess.Popen(prog2, stdout=subprocess.PIPE, stdin=subprocess.PIPE)

这将打开二进制文件作为一个进程,然后您可以使用Python脚本中的发送和接收函数与它进行交互。

我希望这可以帮助遇到类似问题的其他人。