【发布时间】:2018-11-01 21:58:27
【问题描述】:
我正在用 C 语言编写一种终端 shell 语言,称为 tsh(tech shell)。 shell 必须能够处理输出重定向 (">")。我正在使用 fprintf 和 fopen 来完成此任务。 该问题类似于以下内容:
如果我在 shell 中通过 exit 命令使用重定向:
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 但是,如果没有重定向,打印到标准输出就好了。
我在 bash 中 cat 文件的原因是因为 tsh 不支持非内置命令(还),但考虑到在我退出 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() 关闭所有打开的文件并刷新它们的流,但 ^C 中止没有流刷新。您可能希望在停止 shell 执行之前捕获 ^C 并刷新文件。当文件被缓冲时,视频输出应该是无缓冲的,这应该是没有重定向没有问题的原因。
-
尝试在 fprintf 之后调用 fflush。
-
我要关闭并刷新吗?
-
与您的问题无关,但您会发现 libreadline 对您的项目有帮助:tiswww.case.edu/php/chet/readline/rltop.html
标签: c shell printf fopen io-redirection