所以我正在查看我发给他的教授的代码,试图让我们了解如何实现>,<,|支持我们的unix shell。我运行他的代码并对实际发生的事情感到惊讶。
if( pid == 0 )
{
close(1); // close
fd = creat( "userlist", 0644 ); // then open
execlp( "who", "who", NULL ); // and run
perror( "execlp" );
exit(1);
}
这在我当前所在的目录中创建了一个用户列表文件,其中" who"该文件中的数据。我不知道fd和execlp之间的连接在哪里。 execlp是如何设法将信息放入用户列表的? execlp甚至知道用户列表是如何存在的?
答案 0 :(得分:1)
阅读Advanced Linux Programming。它有几个与此问题相关的章节。我们无法用几句话来解释这一切。另请参阅standard stream和process wikipages。
首先,所有system calls(请参阅syscalls(2)以获取列表,并阅读您正在使用的每个系统调用的文档)应该针对失败进行测试。但假设他们都成功了。在close(1);
file descriptor 1(STDOUT_FILENO
)之后,creat("userlist",0644)
免费。因此fd
可能会重复使用它,因此userlist
为1;您已将 stdout 重定向到新行创建的userlist
文件。
最后,您致电execlp(3),致电execve(2)。成功后,将使用新的可执行文件重新启动整个过程(因此为其提供了新的virtual address space),其 stdout 仍然是execve
文件描述符。特别是(除非perror
失败)who > userlist
来电未到达。
所以你的代码有点像运行userlist
的shell正在做什么;它将 stdout 重定向到who
并运行-f
命令。
如果您正在编写shell,请使用strace(1) - 特别是strace -f /bin/sh -c ls
选项 - 来了解完成了哪些系统调用。还可以尝试bash
来查看shell的行为。还要研究现有free software炮弹的源代码(例如sash
和'if_sub': function(a, b, opts) {
if (a.includes(b))
return opts.fn(this);
else
return opts.inverse(this);
}
)。
另见this以及我在那里提供的参考资料。
答案 1 :(得分:0)
execlp
什么都不知道。在执行stdout之前关闭并打开一个文件,因此描述符是对应于stdout的描述符(打开总是返回最低的空闲描述符)。此时,该过程有一个" stdout"插入文件。然后调用exec并替换为整个地址空间,但是一些属性仍然作为描述符,因此要知道who
的代码是使用与文件对应的标准输出执行的。这是重定向由shell管理的方式。
请记住,当您使用printf
时(例如),您永远不会指定stdout究竟是什么......可以是文件,终端等。
答案 2 :(得分:0)
Basile Starynkevitch正确地解释道:
close(1);
后file descriptor 1(STDOUT_FILENO
)免费。所以creat("userlist",0644)
可能会重复使用它......
这是因为,正如Jean-BaptisteYunès写的那样,“打开总是返回最低的自由描述符”。
应该强调的是,教授的代码只有可能有效;如果文件描述符0关闭,则失败。