我正在尝试实现UNIX cat“>”命令,从我的UNIX shell中执行file1.txt > foo.txt
。
我想从用户输入中获取正常的UNIX命令并通过execvp
执行它们(我目前正在做的很好)。
我想添加“>”进入我的shell流程,但是在写入文件后关闭文件时出现问题并将委托返回到命令行以便持续用户输入。有人可以向我解释我在哪里做些傻事?
我意识到为了写入文件,我必须关闭标准,打开新标准,编写文件,然后以某种方式关闭文件的标准输出并重新启用键盘的标准输出以便能够接受用户命令再次..
我的主要功能,只是为了给你一个想法:
int main(int argc, char **argv)
{
printf("[MYSHELL] $ ");
while (TRUE) {
user_input = getchar();
switch (user_input) {
case EOF:
exit(-1);
case '\n':
printf("[MYSHELL] $ ");
break;
default:
// parse input into cmd_argv - store # commands in cmd_argc
handle_user_input();
//determine input and execute foreground/background process
execute_command();
}
background = 0;
}
printf("\n[MYSHELL] $ ");
return 0;
}
这是我的功能获取用户输入的基础。如果找到“>”在cmd_argv数组中,它设置输出标志= 1 并将其从所需的可执行命令中删除:
// get command line input
while ((user_input != '\n') && (buffer_characters < 50)) {
buffer[buffer_characters++] = user_input;
user_input = getchar();
}
// clear buffer
buffer[buffer_characters] = 0x00;
// populate cmd_argv - array of commands
char *buffer_pointer;
buffer_pointer = strtok(buffer, " ");
while (buffer_pointer != NULL) {
cmd_argv[cmd_argc] = buffer_pointer;
buffer_pointer = strtok(NULL, " ");
if(strcmp(cmd_argv[cmd_argc], ">") == 0){
cmd_argv[cmd_argc] = strtok(NULL, " ");
output = 1;
}
cmd_argc++;
if(output){
filename = buffer_pointer; //name of file that we're going to write to.
return;
}
}
execute_command中驱动输出功能的代码注意我在这里给MSG。这似乎是它正在死去的地方:
if (output == 1){
close(1);
file = fopen(filename, "w");
create_process();
output = 0;
printf("IT GOT HERE!!!\n");
fclose(file);
fopen("/dev/null", "r"); // open a new stdin that is always empty
return 1;
}else{
create_process();
return;
}
用于处理前台和后台进程的create_process
void create_process()
{
status = 0;
int pid = fork();
background = 0;
if (pid == 0) {
// child process
if(background) {
printf("no background");
fclose(stdin); // close child's stdin
fopen("/dev/null", "r"); // open a new stdin that is always empty
execvp(*cmd_argv,cmd_argv);
// If an error occurs, print error and exit
fprintf (stderr, "unknown command: %s\n", cmd_argv[0]);
exit(1);
}else if(output == 1){
execvp(*cmd_argv,cmd_argv);
}
else {
execvp(*cmd_argv,cmd_argv);
// If an error occurs, print error and exit
fprintf (stderr, "unknown command: %s\n", cmd_argv[0]);
exit(1);
}
} else {
// parent process, waiting on child process
if (background) {
printf("starting background job %d\n", pid);
jobs_list[jobs_list_size] = pid;
jobs_list_size++;
} else {
waitpid(pid, &status, 0);
}
if (status != 0)
fprintf (stderr, "error: %s exited with status code %d\n", cmd_argv[0], status);
return;
}
}
答案 0 :(得分:1)
你接近错了。您不希望在所有中弄乱父进程的文件描述符,并且您不想使用C的stdio - 您应该使用基于文件描述符的低级调用来完成这项工作
在fork()
之后,在子进程中,您应该执行:
int output_fd = open(filename, O_RDONLY);
if (output_fd > -1) {
dup2(output_fd, STDOUT_FILENO);
close(output_fd);
} else {
perror("open");
}
父母不需要进行任何清理,因为父母的打开文件是单独的。