c - fprintf 不在 ^C 上写入,但在退出时写入

标签 c shell printf fopen io-redirection

我正在用 C 语言编写一种名为 tsh(技术 shell)的终端 shell 语言。 shell 必须能够处理输出重定向(“>”)。我将 fprintf 与 fopen 一起使用来完成此操作。 该问题类似于以下内容:

如果我在 shell 中通过退出命令使用重定向:

tsh$ pwd > out.txt
tsh$ exit

bash$ cat out.txt
/tmp
bash$

但是如果我用 ctrl+c 而不是 exit 做同样的事情:

tsh$ pwd > out.txt
tsh$ ^C

bash$ cat out.txt
bash$

这意味着文件已打开,但当我停止进程时,由于某种原因 tsh 的密码输出没有被写入。

tsh$ pwd 但是,如果没有重定向,则可以很好地打印到标准输出。

我在 bash 中 cat 文件的原因是因为 tsh 不支持非内置命令(目前),但考虑到在我退出 shell 之前内容不会被写入,我不认为它即使我可以从 shell 中 cat 也会工作。

此外,如果 out.txt 尚不存在,它会在两种情况下确实创建,但仍然只在第一种情况下写入。 简而言之,我可以毫无问题地获取对文件的引用,只需写入文件即可。

这是 tsh.c 的当前源代码,用 gcc 编译:

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

const char EXIT[4] = "exit";
const char PWD[3] = "pwd";
const char * DELIM = " \n\r\t";

FILE * outfile, * infile;

char cwd[1024]; //directory to print at beginning of each line

char in[1024]; //user input
char * token;

int main()
{

    while(1)
    {

        outfile = stdout;   
        infile = stdin;

        getcwd(cwd, sizeof(cwd));
        printf("%s$ ",cwd); //prompt with cwd       

        fgets(in, sizeof(in), stdin);

        char * fileref;
        if((fileref = strstr(in,">")))
        {

            fileref = strtok(++fileref, DELIM);
            outfile = fopen(fileref, "w");

        }

        token = strtok(in, DELIM);
        if (token != NULL)
        {
            if(!strncmp(token, EXIT, sizeof(EXIT)))
            {

                token = strtok(NULL, DELIM);
                if (token == NULL)
                {
                    printf("Exiting with status code 0.\n");
                    exit(0);
                }
                else if (isdigit(*token))
                {
                    int code = *token - '0';
                    printf("Exiting with status code %d\n",code);
                    exit(code);
                }
            }
            else if(!strncmp(token, PWD, sizeof(PWD)))
            {
                fprintf(outfile, "%s\n",cwd); //This should get written to the file if I provide a redirection
                continue;
            }

            fputs("\n", outfile);

        }

        fclose(outfile);

    }

}

如果进程没有干净退出,是否有某种内置的回滚机制阻止文件写入?我是否必须拦截并覆盖 ctrl+c 信号?

我知道这里有很多问题和不好的做法,因为这是我第一次使用 C,但如果建议能仅限于我遇到的特定问题,我将不胜感激。

提前致谢。

最佳答案

当您调用 exit() 时,您正在使您的进程终止以一种干净的方式,这除其他事项外确保所有打开的文件都被正确关闭(因此任何缓冲的输出都会被刷新)。

另一方面,当您按下 CTRL+C 时,您正在向您的进程发送一个 SIGINT,并且进程在收到该信号时的默认行为是终止;但这不是一个干净的进程终止(它类似于出现段错误时发生的情况),因此任何打开的文件都没有正确关闭,如果有任何缓冲输出,它将丢失。

在您的应用程序中,您将能够通过修复代码中的逻辑错误来解决您描述的问题:在主 while() 循环中,您正在调用 fopen() 当你在用户输入中遇到 '>' 字符,但是当你执行 'pwd' 命令时你没有关闭 fopen() 返回的文件流,并且在while() 循环的下一次迭代将用 stdout 覆盖文件流指针,有效地泄漏打开的文件。相反,您应该确保在开始循环的下一次迭代之前关闭文件。如下所示:

while(1)
{

    outfile = stdout;
    infile = stdin;

    getcwd(cwd, sizeof(cwd));
    printf("%s$ ",cwd); //prompt with cwd

    fgets(in, sizeof(in), stdin);

    char * fileref;
    if((fileref = strstr(in,">")))
    {

        fileref = strtok(++fileref, DELIM);
        outfile = fopen(fileref, "w");

    }

    token = strtok(in, DELIM);
    if (token != NULL)
    {
        if(!strncmp(token, EXIT, sizeof(EXIT)))
        {

            token = strtok(NULL, DELIM);
            if (token == NULL)
            {
                printf("Exiting with status code 0.\n");
                exit(0);
            }
            else if (isdigit(*token))
            {
                int code = *token - '0';
                printf("Exiting with status code %d\n",code);
                exit(code);
            }
        }
        else if(!strncmp(token, PWD, sizeof(PWD)))
        {
            fprintf(outfile, "%s\n",cwd); //This should get written to the file if I provide a redirection
        }
        else
        {
            fputs("\n", outfile);
        }
    }
    if(fileref)
    {
        fclose(outfile);
    }
}

关于c - fprintf 不在 ^C 上写入,但在退出时写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53109950/

相关文章:

shell - SSH - 一种无需打开单独的 SFTP session 即可传输文件的方法?

printf 格式说明符和 pow 函数中的 C float 或 double

c - 从函数中获取随机字符

javascript - "IOC container"是否只是维护依赖关系?

python - 使用 Python 子进程处理交互式 shell

c - 在 C 中,LARGE_INTEGER.QuadPart 在 printf 中捕获两次

C代码Float to Int(格式化打印字符串)转换小数

c - 为什么全局变量会翻倍两次?

c - Notetaker 漏洞利用问题

linux - 如何使用 sed 作为模式 "/"获取子字符串