如何重定向printf()到文件,然后回到控制台 [英] How to redirect printf() to file and then back to console

查看:1371
本文介绍了如何重定向printf()到文件,然后回到控制台的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个项目,需要我从我的C程序的迷你外壳输出输出到一个文件。 使用 ./ program> file.txt 不会工作

I am working on a project that requires me to have output from within a mini shell on my C program to output to a file. Using ./program > file.txt will NOT work.

我有一个运行小命令的迷你shell程序,因此当有人拥有> filename 在命令结束时,它会将 printf()中的所有文本重定向到文件而不是控制台,然后重定向回到控制台。

I have a mini shell program that runs small commands, and I would like to make it so when someone has a > filename at the end of a command, it will redirect all text from printf() to a file and instead of the console, and then redirect it back into the console.

如何在 C 中完成此操作?

推荐答案

普通shell和fork和exec



如果你有一个正常的shell,你正在使用 fork() execvp() 或其中一个亲戚,那么你应该fork子进程和子进程处理I / O重定向(使用 open()
dup2() dup()
close() ),留下父类的I / O不变。

Normal shell with fork and exec

If you have a normal shell where you're using fork() and execvp() or one of its relatives, then you should fork the child process and in the child handle the I/O redirection (with open(), dup2() or dup(), and close()), leaving the parent's I/O unchanged.

假设您已将命令解析为:

Assuming you have parsed the command into:

char *argv[] = { "simple-command", "arg1", "arg2", 0 };

并将标准输出文件名插入:

and the standard output file name into:

char *file1 = "filename";

然后:

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 */
}

请注意,父级不需要更改其标准输出。

Note that the parent does not need to change its standard output at all.

您也可以使用以下顺序:

You can also use the sequence:

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...






在没有fork和exec的命令中



除了在错误的进程中重定向之外,使用
freopen() 或者 fdopen() 并重新打开 / dev / stdout 将无法工作。由于主程序更改其文件描述符1(标准输出)指向的文件, / dev / stdout 指向程序运行时打开或关闭的更改。


Redirecting built-in commands without fork and exec

Quite apart from redirecting in the wrong process, using freopen() or perhaps fdopen() and reopening /dev/stdout won't work. The file that /dev/stdout points to changes as the program is run and files are opened or closed as the main program changes what its file descriptor 1 (standard output) points at.

如果你真的需要重定向内核的主shell的标准输出,其中 fork() exec() -family函数没有使用,那么你需要做相当于:

If you really need to redirect standard output of the main shell for a built-in, where the fork() and exec()-family functions are not used, then you need to do the equivalent of:

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);






工作代码




Working code


对不起,我不完全理解这段代码(C语言的新手)。你能给出一个完整的例子吗?

I'm sorry, I'm not fully understanding this code (new to C). Can you give a full example?

好的。我已经放弃了一个指针的通用性函数为我第一次编码的内置命令;我认为这可能会让你更多。我拒绝做没有'打印一个错误'函数(虽然我会经常加强报告 errno strerror()以及打印基本错误消息)。

OK. I've foregone the generality of a pointer to function for the built-in command which I first coded; I concluded it would probably confuse you more. I decline to do without a 'print an error' function (though I'd often beef it up to report on errno with strerror() as well as printing the basic error message).

我调用源文件 simpleshell.c 和程序,因此, simpleshell ,但这是过分声称它的作用。

I called the source file simpleshell.c and the program, therefore, simpleshell, but that's over-claiming what it does.

#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;
}



示例输出



Sample output

$ ./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.
$ 

这篇关于如何重定向printf()到文件,然后回到控制台的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆