在shell中运行cat命令时,文件描述符错误

在shell中运行cat命令时,文件描述符错误,c,linux,operating-system,xv6,C,Linux,Operating System,Xv6,我试图在为类Unix操作系统(xV6)编写的shell中实现I/O重定向。在我正在阅读的操作系统手册中,我发现以下代码将在shell中运行以执行cat命令: char *argv[2]; argv[0] = "cat"; argv[1] = 0; if(fork() == 0) { close(0); open("input.txt", O_RDONLY); exec("cat", argv); } 我修改了代码以在shell中运行,该shell的argv数组位于另一个

我试图在为类Unix操作系统(xV6)编写的shell中实现I/O重定向。在我正在阅读的操作系统手册中,我发现以下代码将在shell中运行以执行cat命令:

char *argv[2];
argv[0] = "cat";
argv[1] = 0;
if(fork() == 0) {
    close(0);
    open("input.txt", O_RDONLY);
    exec("cat", argv);
}
我修改了代码以在shell中运行,该shell的argv数组位于另一个函数中,但它保留了该功能。出于某种原因,当我运行
cat
时,shell输出:

cat: -: Bad file descriptor
cat: closing standard input: Bad file descriptor
我对操作系统编程还是新手,所以我并不完全清楚I/O重定向的所有功能,但我认为我的代码应该可以工作。是什么导致了这个问题。我有下面的I/O重定向代码:

case '<':
    ecmd = (struct execcmd*)cmd;
    rcmd = (struct redircmd*)cmd;

    if(fork() == 0){
      close(0);
      open("input", O_RDONLY);
      execvp(ecmd->argv[0], ecmd->argv );
    }
    runcmd(rcmd->cmd);
    break;
编辑2 出于某种原因,此案例代码有效,但我不确定原因:

case '<':
    rcmd = (struct redircmd*)cmd;
    close(rcmd->fd);
    if(open(rcmd->file, rcmd->mode) < 0){
      printf(2, "Cannot open file %s\n", rcmd->file);
      perror(rcmd->file);
      exit(1);
    }
    runcmd(rcmd->cmd);
    break;

case'您不能只关闭stdin然后打开另一个文件。它不会自动成为你的新标准。您想要的是使用syscall dup2,它可以将一个文件描述符“重定向”到另一个文件描述符

int fd = open("input.txt", O_RDONLY);
dup2(fd, 0); // stdin now points to fd
close(fd);
有关更多信息,请参阅。请注意,open和dup2都可能失败,因此如果这是一个问题,您应该检查它们的返回值


编辑:这实际上有时会起作用,因为保证内核始终分配最低的可用文件描述符。但它不是线程安全的,而且通常是糟糕的样式。我建议始终执行dup2,即使在某些情况下,您可以不执行它。

您可以打印出
open()
在代码中返回的值吗?@MarkPlotnick如何检查open()返回的值?在shell中,它只输出错误的描述符消息。您还可以尝试在
strace
下运行程序,以跟踪它进行的所有系统调用:
strace-f-o/some/output/file/name-program[args]
。请参见,您可以将
open
的结果分配给变量,并使用
printf
打印变量的值。在书中查找
fork
示例,了解如何进行变量赋值和调用
printf
。书中的代码实现了一个非常具体的I/O重定向实例:从名为
input.txt
的文件读取。如果该文件不存在,
open
将返回特殊值
-1
,该值不是有效的文件描述符,用于指示错误。第二个代码段更好;它似乎使用用户提供的文件名,并检查从
open
返回的值。你知道为什么这个代码有效吗?它似乎并没有比关闭前一个fd做更多的事情。当你打开一个文件时,内核通常会选择下一个空闲文件描述符。因此,您打开的第一个文件将是fd3,然后是fd4,等等。当您关闭fd0时,它将变为空闲文件,内核将分配它。然而,内核不需要以任何特定的顺序分配FD,这样的编码是非常糟糕的风格。另外,如果你发现我的答案有用,请考虑“接受”它。编辑:显然,内核需要始终选择最低的可用FD。不过,我还是会考虑这种糟糕的风格。
int fd = open("input.txt", O_RDONLY);
dup2(fd, 0); // stdin now points to fd
close(fd);