简单理解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
读取文件描述符所对应的文件内容,即服务器返回的响应报文。
后面简单介绍了一下标准输出和错误输出,如果理解了文件描述符,那么理解标准输出和错误输出就不成问题了。