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

标签 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 数组位于另一个函数中,但它保留了功能。由于某种原因,当我运行 cat < input.txt 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;

编辑

我做了strace -e open ls并得到:

open("/etc/ld.so.cache",    O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libacl.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libpcre.so.3", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libattr.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/proc/filesystems", O_RDONLY)     = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
a.out  sh.c  test
+++ exited with 0 +++

编辑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;

最佳答案

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

int fd = open("input.txt", O_RDONLY);
dup2(fd, 0); // stdin now points to fd
close(fd);

有关更多信息,请参阅 man 2 dup2 。请注意,open 和 dup2 都可能失败,因此如果这是一个问题,您应该检查它们的返回值。

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

关于c - 在 shell 中运行 cat 命令时文件描述符错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32571083/

相关文章:

linux - 将 linux box 配置为具有静态 ip

c++ - C/C++标准库中的缓冲

c - 如何将.text段以外的段中的执行代码放到.text段的中间

python - 在 python 中获取 Windows 版本的更好方法是什么?

memory - 为什么我们需要虚拟内存?

c - C语言指针中的*p++,*++p,++*p有什么区别?

c - c 中奇怪的左移位

operating-system - 抢占式和非抢占式内核 VS 抢占式和非抢占式调度

c - 关于我的C程序跳过空行的问题

c++ - 如何制作一个可以在 C 库中用作回调的 wxWidget 方法?