我只是试图调和这两个看似相似的概念。
在Bash中,允许任意重定向,重要的是使用所选的文件描述符号。但是,在Linux中,调用进程不能选择open调用(AFAIK)返回的值。
因此,Bash数字是否与系统调用返回的fd编号相同?如果没有,有什么区别?
发布于 2019-04-18 04:35:52
下面是一个小小的实验,可以说明在bash中打开文件描述符时发生了什么,并选择了许多内容:
> cat test.txt
foobar!
> cat test.sh
#!/bin/bash
exec 17<test.txt
read -u 17 line
echo "$line"
exec 17>&-
> strace ./test.sh
//// A bunch of stuff omitted so we can skip to the interesting part...
open("test.txt", O_RDONLY) = 3
fcntl(17, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(3, 17) = 17
close(3) = 0
fcntl(17, F_GETFD) = 0
ioctl(17, TCGETS, 0x7ffc56f093f0) = -1 ENOTTY (Inappropriate ioctl for device)
lseek(17, 0, SEEK_CUR) = 0
read(17, "foobar!\n", 128) = 8
write(1, "foobar!\n", 8foobar!) = 8
fcntl(17, F_GETFD) = 0
fcntl(17, F_DUPFD, 10) = 10
fcntl(17, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
close(17) = 0回答您问题的部分是在哪里调用open() on test.txt,它返回的值为3。如果您这样做,您很可能在C程序中得到这个值,因为文件描述符0、1和2(即stdin、stdout和stderr)都是最初打开的。数字3只是下一个可用的文件描述符。
我们在bash脚本的strace输出中也看到了这一点。bash所做的不同之处在于,它随后调用fcntl(17, F_GETFD)来检查文件描述符17是否已经打开(因为它希望将fd用于test.txt)。然后,当fcntl返回指示没有这样的fd是打开的EBADF时,bash知道它可以自由使用它。因此,它调用dup2(3, 17)使fd 17成为fd 3的副本。最后,它调用fd 3上的close()再次释放它,将fd 17 (仅fd 17)作为test.txt的打开文件描述符。
因此,对您的问题的回答是,bash文件描述符并不是与其他人使用的“正常”文件描述符不同的特殊生物。事实上,他们也是一样的。您可以很容易地在C程序中使用相同的技巧来打开您选择的文件描述符号的文件。
此外,值得指出的是,bash在调用open()时并没有真正选择自己的文件描述符。它必须与其他人一样,用open()返回的任何内容来解决问题。在bash脚本中,真正要做的就是(通过dup2())进行一些冒烟和镜像,以使您看起来像是选择了自己的文件描述符。
https://stackoverflow.com/questions/55739026
复制相似问题