当您测试它时,您正在使用连接到终端的 stdin、stdout 和 stderr 来运行程序。碰巧该文件描述所有 3 个文件描述符都是读/写。
fd 0 并没有什么神奇之处可以阻止文件描述符的读/写。
我认为 shell 可以分别打开只读和只写终端,而不是运行所有 3 个标准文件描述符都是同一读写文件描述的重复项的程序。 (设置为dup2 http://man7.org/linux/man-pages/man2/dup.2.html)。但这不是 bash(或启动 bash 的终端仿真器)的设计方式。
尝试运行你的sys_read(1, ...)
stdin 是一个管道或文件,绝对只为读取而打开,而 stdout 是一个只为写入而打开的 fd 版本。
$ echo foo | strace ./read1 > foo.out
execve("./read1", ["./read1"], 0x7fff68953560 /* 52 vars */) = 0
strace: [ Process PID=31555 runs in 32 bit mode. ]
read(1, 0x80490ac, 5) = -1 EBADF (Bad file descriptor)
write(1, "\0\0\0\0\0", 5) = 5
exit(0) = ?
+++ exited with 0 +++
So read(1, num, 5)
回-EBADF
(错误的文件描述符),因为 fd 1 是只写 fd,在该进程的 fork/execve 之前由 shell 打开。write(1, ...)
仍然发生,因为你的程序没有做任何错误检查。 (那很好;我们有类似的工具strace
所以我们在尝试系统调用时可以偷懒)。
但请注意重定向 stdin 没有任何区别;你的程序从不使用fd 0!
当 fd 1 连接到 tty 时,无论输入重定向如何,从中读取都会从终端读取。
$ echo test | strace ./read1
execve("./read1", ["./read1"], 0x7ffc3c42d620 /* 52 vars */) = 0
strace: [ Process PID=31462 runs in 32 bit mode. ]
read(1, # it blocked here until I pressed return
"\n", 5) = 1
write(1, "\n\0\0\0\0", 5
) = 5
exit(0) = ?
+++ exited with 0 +++
在另一个终端中read1
被暂停等待read()
回来:
$ ll /proc/$(pidof read1)/fd
total 0
lr-x------ 1 peter peter 64 Feb 22 18:17 0 -> pipe:[13443590]
lrwx------ 1 peter peter 64 Feb 22 18:17 1 -> /dev/pts/17
lrwx------ 1 peter peter 64 Feb 22 18:17 2 -> /dev/pts/17
lrwx------ 1 peter peter 64 Feb 22 18:17 49 -> socket:[405352]
lrwx------ 1 peter peter 64 Feb 22 18:17 53 -> socket:[405353]
请注意 fd 1 上的 RWX:该符号链接的权限反映了它是读、写还是读+写 fd。