C 如何将printf()重定向到文件,然后再返回控制台

C 如何将printf()重定向到文件,然后再返回控制台,c,file,io,console,printf,C,File,Io,Console,Printf,我正在从事一个项目,该项目要求我在我的C程序上有一个迷你shell中的输出,以输出到一个文件。使用./program>file.txt将不起作用 我有一个运行小命令的迷你shell程序,我希望这样,当有人在命令末尾有一个>文件名时,它会将printf中的所有文本重定向到一个文件,而不是控制台,然后将其重定向回控制台 如何在C语言中实现这一点?您可以使用 完成后,可以按如下方式撤消重新分配: freopen("/dev/stdout", "w", stdout); 在Unix/Linux系统上。

我正在从事一个项目,该项目要求我在我的C程序上有一个迷你shell中的输出,以输出到一个文件。使用./program>file.txt将不起作用

我有一个运行小命令的迷你shell程序,我希望这样,当有人在命令末尾有一个>文件名时,它会将printf中的所有文本重定向到一个文件,而不是控制台,然后将其重定向回控制台

如何在C语言中实现这一点?

您可以使用

完成后,可以按如下方式撤消重新分配:

freopen("/dev/stdout", "w", stdout);
在Unix/Linux系统上。我不确定是否有一种可移植的方法可以恢复

更新

如果可能,您可以使用fprintf而不是printf,根据需要为所需文件提供stdout或句柄。

带fork和exec的普通shell 如果您使用的是普通shell和/或它的一个亲戚,那么您应该分叉子进程,并在子进程中处理I/O重定向, 或dup,以及 ,使父级的I/O保持不变

假设您已将命令解析为:

char *argv[] = { "simple-command", "arg1", "arg2", 0 };
并将标准输出文件名转换为:

char *file1 = "filename";
然后:

工作代码
很抱歉,我不完全理解C语言的新代码。你能举个完整的例子吗

嗯。对于我第一次编写的内置命令,我已经放弃了函数指针的一般性;我的结论是,这可能会让你更加困惑。我拒绝不使用“打印错误”功能,尽管我经常使用strerror来增强它,以报告错误,并打印基本错误消息

我调用了源文件simpleshell.c,因此程序名为simpleshell,但它的功能就到此为止了

#include <stdarg.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

static int err_report(const char *fmt, ...);

static int redirect_echo_to_file(char **argv, char *file)
{
    /* Connect standard output to given file */
    fflush(stdout);
    int fd1 = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd1 < 0)
        return err_report("Failed to open %s for writing\n", file);
    int fd2 = dup(STDOUT_FILENO);
    if (fd2 < 0)
        return err_report("Failed to duplicate standard output\n");
    if (dup2(fd1, STDOUT_FILENO) < 0)
        return err_report("Failed to duplicate %s to standard output\n", file);
    close(fd1);

    /* Write to standard output */
    char *pad = "";
    while (*argv != 0)
    {
        printf("%s%s", pad, *argv++);
        pad = " ";
    }
    putchar('\n');

    /* Reconnect original standard output */
    fflush(stdout);
    if (dup2(fd2, STDOUT_FILENO) < 0)
        return err_report("Failed to reinstate standard output\n");
    close(fd2);
    return 0;
}

int main(void)
{
    char *file1 = "file.01";
    char *file2 = "file.02";
    char *arguments[] = { "Hello", "world!", "This", "is your", "echo", "speaking." };
    printf("This is the surrogate shell at work\n");
    printf("Echo the same message to two different files (%s and %s)\n", file1, file2);
    if (redirect_echo_to_file(arguments, file1) != 0 ||
        redirect_echo_to_file(arguments, file2) != 0)
        return -1;
    printf("Regular shell output on standard output.\n");
    printf("Please check %s and %s for a special message.\n", file1, file2);
    return 0;
}

static int err_report(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    return -1;
}

,-上下文中的键是dup2,它仅在fork之后才需要,因此父级不必使用自己的stdout进行futz。@BLUEPIXY:使用freopen works访问文件;之后你怎么换回来?至少还有更多的事情要做,而不仅仅是打电话给freopen。@JonathanLeffler你能举个例子吗?我以前试过使用fork和dup2,但似乎不起作用;之后你怎么换回来?至少还有更多的事情要做,而不仅仅是打电话给弗罗普;但是当您第二次调用freopen时,/dev/stdout指向文件…@JonathanLeffler:/dev/stdout是系统上的一个设备。C引用为stdout的文件句柄已指向该文件。or/dev/tty,con或con:for windowsGo试试看……我认为您最终需要dup或dup2,然后您可以使用freopen on/dev/fd/N,其中N是您首先将stdout复制到的值。有fileno和fdopen,这可能也是相关的。但我认为这个问题没有抓住重点——需要处理的是子过程。在纯POSIX shell中,您可以使用:{exec 3>&1>desiredFileName;executecommands…;exec 1>&3>&-;}您能解释一下execvpargv[0],argv;是为了?运行命令…您有一个shell,可以运行小命令,您可以说,您需要能够运行一个小命令,其输出将进入一个文件,而父进程将继续在其他位置写入。如果你的意思是“使用I/O重定向处理内置命令,但不执行外部进程”,那么你需要这么说。我得到了一系列错误,比如警告:函数“fork”的隐式声明,它也在运行自己的命令,而不是真正的linux命令。OK;所以它不是一个普通的外壳。见对我的答复的修正案。这是好的,你得到了叉子的警告,并注意到了警告;非常感谢。fork的相关标题为;同上,dup等人。但是,OpenRequirements。很抱歉,我不完全理解C语言的新代码。你能给出一个完整的例子吗?
if ((pid = fork()) < 0)
    ...report error...
else if (pid == 0)
{
    int fd = open(file1, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd < 0)
        ...report error and exit...
    dup2(fd, STDOUT_FILENO);
    close(fd);
    execvp(argv[0], argv);
    ...report error and exit...
}
else
{
    /* Do whatever the parent needs to do */
}
close(STDOUT_FILENO);
int fd = open(file1, O_WRONLY | O_CREAT | O_TRUNC, 0644); // Or 0666
if (fd < 0)
    ...report error and exit...
if (fd != STDOUT_FILENO)
    ...standard input must have been closed too...
fflush(stdout);  // Safety precaution
int fd1 = open(file1, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd1 < 0)
    ...report error and do not continue...
int fd2 = dup(STDOUT_FILENO);
if (fd2 < 0)
    ...report error and do not continue...
if (dup2(fd2, STDOUT_FILENO) < 0)
    ...report error and do not continue...
close(fd1);  // check for error?
...do whatever operations need standard output redirected...
fflush(stdout);  // Safety precaution
if (dup2(fd1, STDOUT_FILENO) < 0)  // Bug fixed!
    ...report error and do not continue...
close(fd2);
#include <stdarg.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

static int err_report(const char *fmt, ...);

static int redirect_echo_to_file(char **argv, char *file)
{
    /* Connect standard output to given file */
    fflush(stdout);
    int fd1 = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd1 < 0)
        return err_report("Failed to open %s for writing\n", file);
    int fd2 = dup(STDOUT_FILENO);
    if (fd2 < 0)
        return err_report("Failed to duplicate standard output\n");
    if (dup2(fd1, STDOUT_FILENO) < 0)
        return err_report("Failed to duplicate %s to standard output\n", file);
    close(fd1);

    /* Write to standard output */
    char *pad = "";
    while (*argv != 0)
    {
        printf("%s%s", pad, *argv++);
        pad = " ";
    }
    putchar('\n');

    /* Reconnect original standard output */
    fflush(stdout);
    if (dup2(fd2, STDOUT_FILENO) < 0)
        return err_report("Failed to reinstate standard output\n");
    close(fd2);
    return 0;
}

int main(void)
{
    char *file1 = "file.01";
    char *file2 = "file.02";
    char *arguments[] = { "Hello", "world!", "This", "is your", "echo", "speaking." };
    printf("This is the surrogate shell at work\n");
    printf("Echo the same message to two different files (%s and %s)\n", file1, file2);
    if (redirect_echo_to_file(arguments, file1) != 0 ||
        redirect_echo_to_file(arguments, file2) != 0)
        return -1;
    printf("Regular shell output on standard output.\n");
    printf("Please check %s and %s for a special message.\n", file1, file2);
    return 0;
}

static int err_report(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    return -1;
}
$ ./simpleshell
This is the surrogate shell at work
Echo the same message to two different files (file.01 and file.02)
Regular shell output on standard output.
Please check file.01 and file.02 for a special message.
$ cat file.01
Hello world! This is your echo speaking.
$ cat file.02
Hello world! This is your echo speaking.
$