简单理解linux文件描述符
文件描述符
文件描述符可以简单理解为一个不透明的句柄(我自己理解的),当我们创建文件或者打开已有文件的时候,内核就会向进程返回文件描述符,它可以简单理解为是操作系统为为文件创建的索引。
在linux
系统中,每个进程都有3个默认的文件描述符,分别用0
、1
、2
来表示,含义分别如下:
0
:标准输入,对应的设备文件为/dev/stdin
。
1
:标准输出,对应的设备文件为/dev/stdout
。
2
:错误输出,对应的设备文件为/dev/stderr
。
除了默认文件描述符以外,还能为进程创建其他文件描述符,甚至是tcp
套接字。
在linux
中,可以查看/proc/进程号/fd/
下的文件来查看该进程创建的文件描述符。
比如在终端中使用vim
打开了一个新的文件123
。除了0
、1
、2
等默认文件描述符外,还有其他的描述符,比如:
bash
3 -> /root/.123.swp
如果在终端中打开了一个套接字,比如telnet
,那么也会有相应的文件描述符中,比如:
bash
4 -> socket:[179916]
这个套接字指向的是一个inode
号,可以使用lsof
等工具查询。
如果你还是不理解文件描述符,那么请看下面这个例子:
在linux
中,使用exec
可以创建文件描述符,比如:
bash
exec 3<>/root/123.txt
上述命令创建了一个文件描述符为3
的句柄,这个句斌属于操作系统,可以为外部程序锁调用,可以使用查看/dev/fd/
目录下查看该信息,比如:
bash
0 -> /dev/pts/1
1 -> /dev/pts/1
2 -> /dev/pts/1
3 -> /root/123.txt
可以直接向/dev/fd/3
写入数据的方式来存储数据,比如;
bash
echo 123456 > /dev/fd/3
上述将123456
这个字符串以重新向的方式写入/dev/fd/3
文件中。
再看实际的文件,该文件中已经有了该字符串。
bash
# cat /root/123.txt
123456
#
使用完成后,记得关闭该文件描述符。
bash
exec 3>&-
标准输出和错误输出
上述有了文件描述符的铺垫,使用重定向就比较简单了。
在bash
中,标准输出使用>
关键字,比如:
bash
ls -l > filename
上述命令将ls -l
的标准输出写入到文件filename
中(linux
一切皆文件)
而错误输出的关键字是2>
关键字, 比如:
bash
abcd 2> filename
假设不存在abcd
这个命令,则使用该操作就会将错误输出重定向到filename
中。
上述的>
和2>
关键字使用的时候都会将文件原始数据给清理掉。
除此之外,还有追加标准输出、追加错误输出,则分别使用>>
和2>>
关键字来表示,例如:
bash
ls -l >> filename
上述命令将ls -l
的标准输出追加到文件filename
中,不会清理掉原文件的内容。
而错误追加输出也是一样的:
bash
abcd 2>> filename
在bash
中,标准输出和错误输出可以执行同一个文件,比如,下面这条语句:
bash
comamnd > filename 2> &1
它表示将 command
的标准输出结果都重定向到文件 filename
中,然后将标准错误重定向到与标准输出相同的位置,即 filename
文件。这里需要注意的是,2>&1
中间不能有空格,其中 2>
表示标准错误输出,&1
指的是刚刚设置的标准输出文件描述符。
在bash
中,使用&>
可以实现上述功能,你可以将其理解为语法糖:
bash
comamnd &> filename
总结
简单介绍了一下文件描述符,这是一个非常有意思的事情,将其理解为一个不透明的句柄就可以了。linux
操作系统为每一个进程都创建了3个文件描述符,分别是标准输入:0
、标准输出1
和错误输出2
。如果程序后期打开了新的文件,则会在进程描述符下创建新的fd
文件,比如:/proc/进程Id/fd
下,linux
下一切皆文件,甚至是tcp
句柄,比如:
bash
exec 3<>/dev/tcp/127.0.0.1/80
这个命令表示创建了一个读写的文件描述符,id
为3
,指向/dev/tcp/127.0.0.1/80
这个文件,这个文件表示建立一个127.0.0.1:80
的tcp
连接。
bash
echo -e "GET / HTTP/1.1\r\n\r\n" >&3
向这个文件描述符写入简单的http
请求报文。
bash
cat <&3
读取文件描述符所对应的文件内容,即服务器返回的响应报文。
后面简单介绍了一下标准输出和错误输出,如果理解了文件描述符,那么理解标准输出和错误输出就不成问题了。