我正在用 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/