[英]Unix Shell Implementing Cat in C - File Descriptor Issue
我已经完成了Unix shell的实践实现,除了在cat
输出到文件时实现cat
存在问题 。 IE: cat foo.txt > bar.txt
foo
的内容输出到bar
。
让我们从主要功能开始,然后定义子方法:
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;
}
handle_user_input
只是填充cmd_argv
数组以执行user_input
,如果用户希望输出到文件,则删除>
并设置output
标志。 这就是这种方法的本质:
while (buffer_pointer != NULL) {
cmd_argv[cmd_argc] = buffer_pointer;
buffer_pointer = strtok(NULL, " ");
if(strcmp(cmd_argv[cmd_argc], ">") == 0){
printf("\nThere was a '>' in %s @ index: %d for buffer_pointer: %s \n", *cmd_argv,cmd_argc,buffer_pointer);
cmd_argv[cmd_argc] = strtok(NULL, " ");
output = 1;
}
cmd_argc++;
if(output){
filename = buffer_pointer;
printf("The return of handling input for filename %s = %s + %s \n", buffer_pointer, cmd_argv[0], cmd_argv[1]);
return;
}
}
然后调用execute_command
,解释现在填充的cmd_argv
。 只是为了让您了解大局。 显然,这些情况都不匹配,并且调用create_process
方法:
int execute_command()
{
if (strcmp("pwd", cmd_argv[0]) == 0){
printf("%s\n",getenv("PATH"));
return 1;
}
else if(strcmp("cd", cmd_argv[0]) == 0){
change_directory();
return 1;
}
else if (strcmp("jobs", cmd_argv[0]) == 0){
display_job_list();
return 1;
}
else if (strcmp("kill", cmd_argv[0]) == 0){
kill_job();
}
else if (strcmp("EOT", cmd_argv[0]) == 0){
exit(1);
}
else if (strcmp("exit", cmd_argv[0]) == 0){
exit(-1);
}
else{
create_process();
return;
}
}
很简单吧?
create_process
是我遇到问题的地方。
void create_process()
{
status = 0;
int pid = fork();
background = 0;
if (pid == 0) {
// child process
if(output){
printf("Output set in create process to %d\n",output);
output = 0;
int output_fd = open(filename, O_RDONLY);
printf("Output desc = %d\n",output_fd);
if (output_fd > -1) {
dup2(output_fd, STDOUT_FILENO);
close(output_fd);
} else {
perror("open");
}
}
printf("Executing command, but STDOUT writing to COMMAND PROMPT instead of FILE - as I get the 'open' error above \n");
execvp(*cmd_argv,cmd_argv);
// If an error occurs, print error and exit
fprintf (stderr, "unknown command: %s\n", cmd_argv[0]);
exit(0);
} else {
// parent process, waiting on child process
waitpid(pid, &status, 0);
if (status != 0)
fprintf (stderr, "error: %s exited with status code %d\n", cmd_argv[0], status);
}
return;
}
我打印的output_fd = -1
,我设法在else perror("open")
得到perror("open")
: open: No such file or directory
。 然后,当我显示到控制台时,它会打印出它是"writing to COMMAND PROMPT instead of FILE"
。 然后执行处理cat foo.txt
execvp
,但将其打印到控制台而不是文件。
我意识到此时不应该这样做,因为不希望output_fd = -1
并且应该返回另一个值; 但是我无法弄清楚如何正确使用文件描述符,以便通过cat foo.txt > bar.txt
打开一个新文件/现有文件并写入文件,就像回到命令行的stdin一样。
我已经设法输出到文件,但是随后又丢失了正确的标准输入。 有人可以把我引导到这里吗? 我觉得我正在做一些愚蠢的事情,我做错了或正在寻找。
非常感谢任何帮助。
如果要写入文件,为什么要使用O_RDONLY? 我的猜测是您应该使用类似以下内容的方法:
int output_fd = open(filename, O_WRONLY|O_CREAT, 0666);
(0666用于在创建时设置访问权限)。
显然,如果您无法打开某个目标文件,则不应启动该命令。
首先,我注意到的很明显的事情是您已经打开了文件O_RDONLY。 输出效果不好!
其次,重定向输出的基本过程是:
最后,您真的将命令名作为全局变量传递了吗? 我认为,一旦您尝试实施cat foo | ( cat bar; echo hi; cat ) > baz
就会再次困扰您cat foo | ( cat bar; echo hi; cat ) > baz
cat foo | ( cat bar; echo hi; cat ) > baz
或诸如此类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.