我正在用C编写一种名为tsh(技术外壳)的终端外壳语言。外壳程序必须能够处理输出重定向(“>”)。我将fprintf与fopen结合使用来完成此任务。 该问题类似于以下内容:
如果我通过退出命令在外壳程序中使用重定向:
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的pwd的输出。
tsh$ pwd
确实可以在没有重定向的情况下打印到stdout。
我把文件放在bash中的原因是因为tsh不支持非内置命令(但是),但是考虑到内容直到退出shell才被写入,所以我不认为它即使我能从外壳上抓猫也能正常工作。
此外,如果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,但是如果将建议限制在我遇到的特定问题上,我将不胜感激。
谢谢。
答案 0 :(得分:0)
^ C正在将KILL信号发送到您的程序(KILL)。您应该使用^ D代替输入(EOF)。
fgets() returns s on success, and NULL on error or when end of file occurs while no characters have been read.
因此,您必须使用:while (fgets(in, sizeof(in), stdin)) {}
答案 1 :(得分:0)
调用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);
}
}