在正确的位置将输入回声输入到输出中

Echo input into output, at the right place

提问人:Romildo 提问时间:2/13/2023 最后编辑:Romildo 更新时间:2/13/2023 访问量:98

问:

我想在读取程序的那一刻将给定给程序的输入插入到其输出中。

例如,给定程序:

#include <stdio.h>

int main() {
  double x, y;
  printf("Soma de dois números:\n");
  printf("Digite o primeiro número: ");
  scanf("%lf", &x);
  printf("Digite o segundo número: ");
  scanf("%lf", &y);
  double soma = x + y;
  printf("%lf + %lf = %lf\n", x, y, soma);
  return 0;
}

当它使用输入重定向运行时,我希望将输入插入到输出中,如下所示:

$ echo -e "10\n25\n" | ./a.out
sum of two numbers
first number: 12
second number: 25
12.000000 + 25.000000 = 37.000000

是否有任何库或工具可以帮助我?

编辑上下文:我打算用它来纠正编程课程中的程序练习。我想查看/显示程序输入和输出,就好像它在交互式控制台中运行一样,输入是交互式键入的,尽管输入是从文本文件重定向的。

C 用户输入 IO 重定向

评论

0赞 Eric Postpischil 2/13/2023
您希望将程序从标准输入流接收的输入回显到标准输出流?最简单的方法是简单地在程序中插入打印调用。假设您使用的是 ,您可以通过打印扫描值来重建输入,尽管这会产生差异,例如无论用户输入的是“12”、“12”还是“012”,都会显示“12”。要精确回显输入,您需要停止使用 。你可以一个接一个地获取每个字符并回显它,然后你会解析这些字符......scanfscanf
0赞 Eric Postpischil 2/13/2023
...或者,如果它适合您的目的,您可以使用 echo 一次读取一行,然后使用 解析该行。另一种选择是将标准库输入例程替换为您自己的回显输入版本,但这属于程序构造的另一个级别,并且可能比您想要的要多。您应该使用上下文信息更新问题,说明您试图通过此实现的目标以及上面的逐行或其他建议是否足够。fgetssscanf
0赞 Jonathan Leffler 2/13/2023
没有一种简单的方法可以做到这一点。问题在于,当您在终端键入时,终端驱动程序会回显键入的字符。当您有 I/O 重定向 (从管道或文件) 时,不涉及终端驱动程序,并且磁盘驱动程序和管道代码都不会回显到标准输出。一种选择可能是使用伪终端作为程序的输入——但我没有尝试过,所以这可能不起作用。或者,您可以测试输入是否为终端,如果它是终端,则不做任何特殊操作,如果是,则回显输入的结果。POSIX有帮助。isatty()
0赞 Barmar 2/13/2023
在 Unix 上,您可以使用该函数来检查标准输入是否来自终端。如果是终端,则显示提示并读取输入(终端驱动程序将回显输入)。如果没有,请读取输入,然后显示附加输入的提示。isatty()
0赞 Romildo 2/13/2023
我已经编辑了这个问题,以便更好地进行上下文化。

答:

1赞 Jonathan Leffler 2/13/2023 #1

正如我在评论中指出的那样:

没有一种简单的方法可以做到这一点。问题在于,当您在终端键入时,终端驱动程序会回显键入的字符。当具有 I/O 重定向(从管道或文件)时,不涉及终端驱动程序,并且磁盘驱动程序和管道驱动程序都不会回显到标准输出。

一种选择可能是使用伪终端作为程序的输入——但我没有尝试过,所以这可能不起作用。它的设置也相当繁琐(尽管 Linux 上可能有一个实用程序,特别是可以完成这项工作)。

或者,您可以测试输入是否为终端,如果它是终端,则不做任何特殊操作,如果是,则回显输入的结果。POSIX 函数 isatty() 确定给定的文件描述符是否为终端。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    printf("Enter a number: ");
    double d;
    if (scanf("%lf", &d) != 1)
    {
        fprintf(stderr, "Failed to read a number!\n");
        exit(EXIT_FAILURE);
    }
    if (!isatty(STDIN_FILENO))
        printf("%lf\n", d);
    printf("You entered: %lf\n", d);
    return 0;
}

将其保存为源文件后,我可以运行:tty47.c

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common tty47.c -o tty47
$ tty47
Enter a number: 2.718282
You entered: 2.718282
$ echo "3.141593" | tty47
Enter a number: 3.141593
You entered: 3.141593
$ tty47 <<<'1.618034'
Enter a number: 1.618034
You entered: 1.618034
$

第一次运行接受我在终端键入的输入,并由终端驱动程序回显。另外两个运行知道输入分别来自管道和文件,并且它们会回显输入。请注意,不能保证回声与用户输入的内容完全相同——我通过输入小数点后 6 位的数字来作弊。使用较少的地方,你会得到尾随的零;使用更多,结果是四舍五入的。您必须决定这是否重要。

另一种策略是读取输入 using or equivalent 并回显每个字符,如果输入不是终端,则使用 or equivalent 回显每个字符,然后用于解析数据。这绝对是更繁琐的。getchar()putchar()sscanf()