Bash 单命令行解释(3)--重定向
这是翻译系列文章的第3篇,参考原文链接 。
翻译的系列文章列表:
- Bash 单命令行解释,第一部分:文件操作
- Bash 单命令行解释,第二部分:字符串操作
- Bash 单命令行解释,第三部分:重定向(本篇)
Bash 单命令行解释,第三部分:重定向
这是 Bash One-Liners Explained 系列文章的第3篇。本文中将讲授 输入/输出重定向 。我将利用 bash 最佳实践,多变的 bash 方言和 bash 命令技巧,展示仅利用 bash 内建命令和外部程序命令构建命令流完成各种各样的任务需求。
参见系列文章的第一篇 Bash 单命令行解释,第一部分:文件操作 了解我的初衷。若这个系列文章完成后,我将放出其同名的电子书。正如我创作的其它系列文章-- awk,sed 和 perl 一样,我的电子书 有 pdf 格式及方便在手机上看的格式(mobi 和 epub)。同时,像 perl1line.txt 一样,也有纯文本 txt 格式的文档。
也可参考我其它的高效使用 bash 的系列文章:
- Working Productively in Bash's Emacs Command Line Editing Mode (comes with a cheat sheet)
- Working Productively in Bash's Vi Command Line Editing Mode (comes with a cheat sheet)
- The Definitive Guide to Bash Command Line History (comes with a cheat sheet)
开始学习
第三部分:重定向
当你理解了 文件描述符(file descriptors) 的操作,将会觉得使用 bash 的重定向非常简单。当 bash 启动时,它将默认打开 3 个标准文件描述符 :stdin(0号文件描述符) ,stdout(1号文件描述符) ,stderr(2号文件描述符) 。你可以打开更多的文件描述符(诸如:3,4,5 ...),也可以关闭它们,你可以拷贝文件描述符 ,也可以从它那里读或写入到它。
文件描述符 总是指向某些文件(除非文件被关闭)。通常,bash 启动时会把3个标准文件描述符:stdin,stdout,stderr 通通指向终端。输入(stdin)来自终端的键入内容,所有的输出(stdout,stderr)显示在终端里。
假定你的终端是 /dev/tty0 ,下面是终端与标准文件描述符之间的关系示意图:
当 Bash 执行一条命令时,它会 分支(fork) 一个子进程,这个子进程继承 fork 它的父进程的一切标准文件描述符(关于 fork ,详情参考手册命令 man 2 fork
)。首先按照命令行指示进行 重定向输入/输出 后才 执行(exec) 命令(关于 exec ,详情参考手册命令 man 3 exec
)。
对于想 bash 重定向 操作进阶的你,永远心中有个蓝图 -- 当重定向发生时,标准文件描述符如何变化 --,这个蓝图将极大地帮助到你。
1. 重定向标准输出到一个文件
$ command >file
符号 > 是输出重定向操作符。bash 先尝试打开重定向指向的文件(这里是文件 file)并可写入,如果成功,Bash 将 command
命令子进程的标准输出文件描述符指向打开的文件。如果失败,整个命令失败退出,结束子进程。
命令行 command >file
等同于命令行 command 1>file
。数字 1 代表 stdout,它是标准输出文件描述符 stdout 的文件描述符号。
下面是标准文件描述符改变的蓝图示意。Bash 打开文件 file 并确定可写入后,替换子进程的标准输出文件描述符1为 file 文件的文件描述符,自此,命令的所有输出将写入文件 file 中。
通常,你可使用形如 "command n>file" 的命令,表示此命令的 n 号标准输入/输出文件描述符指向 file 。
举例:
$ ls > file_list
重定向 ls
命令的输出到 file_list 文件(命令的输出写入到文件)。
2. 重定向命令的标准错误输出到文件
$ command 2> file
这里,将命令的标准错误输出(stderr 号 2)文件描述符重定向到文件。这里的数字 2 代表标准错误输出文件描述符。
下面是标准文件描述符表改变蓝图:
Bash 打开文件 file 并确定可写入后,替换子进程的标准错误输出文件描述符2为 file 文件的文件描述符,自此,命令的所有错误输出由原来写入 stderr 中改写入文件 file 中。
3. 重定向标准输出和标准错误输出到文件
$ command &>file
上面这行命令中 "&>" 表示把所有的标准输出文件描述符(stdout 和 stderr )重定向到 file 文件描述符。&> 是 Bash 快速引用所有标准输出描述符(1 和 2)的简写。
下图是标准文件描述符改变示意图:
这里你看到所有的标准输出( stdout 和 stderr )都指向 file 文件的文件描述符。
有不同的几个方法将所有标准输出重定向到一个目标。可以按顺序一个接一个地重定向:
$ command >file 2>&1
上面命令是较通用的重定向所有标准输出到文件的方法。首先,标准输出(stdout)重定向到 file 文件(这步是先运行 ">file" 的结果)。之后,标准错误输出(stderr)重定向到 已重定向过的 stdout(&1) 上 (通过 "2>&1") 。因此,所有的标准输出都重定向到 file 上。
Bash 在命令行解析时,发现有多个重定向操作时,按从左到右的顺序依次解释处理。让我们按 Bash 执行顺序,单步分析,更好地理解它。一开始,Bash 在执行命令前,其3个标准输入/输出文件描述符都指向终端。示意图如下:
首先,Bash 处理第一个重定向 ">file" 。之前,我们见过这个示意图。它的标准输出(stdout)指向终端:
下一步解释处理重定向操作 "2>&1",这个操作的含义是使标准错误输出文件描述符(stderr 号 2)成为 1号标准输出文件描述符(stdout)的副本(重定向 2 到 1 的当前引用)。我们得到如下示意图:
所有的标准输出描述符都重定向到 file 文件。
然而,小心不要把 command >file 2>&1
写成 command 2>&1 >file
,它们是不同的!
Bash 对重定向指令的顺序敏感!后一命令仅仅把标准输出1(stdout) 重定向到 file 文件,而 标准输出2(stderr) 仍然输出到终端。理解为什么,让我们再进行单步分析,看看发生了什么。初始示意图如下:
Bash 从左到右一步步处理重定向,首先遇到 "2>&1" ,因此将 2 (stderr) 重定向与 1(stdout) 相同,即都指向终端,示意图如下:
现在,Bash 看到第2个重定向操作符 ">file" ,它重定向 1(stdout) 到 file 文件,示意图如下:
看到了什么,1(stdout) 重定向到了 file 文件,但 2(stderr) 仍指向终端,所有写到 stderr 的都显示到屏幕。所以,在使用重定向时,要非常非常小心给出它的操作循序!
另外在 Bash 中要注意:
$ command &>file
操作含义,与下面命令形式完全相同:
$ command >&file
但推荐第一种形式写法。
4. 舍弃命令的屏幕输出
$ command > /dev/null
特殊文件 /dev/null 抛弃所有写入它的内容(译注:可认为 /dev/null 是一个大小恒为0的文件,向它写入任何内容,它都会将它清空,保持文件大小为 0 。把它拷贝覆盖已有文件的动作也是把文件内容清空的方法)。下面是标准文件描述符示意图:
类比地,组合之前学过的命令,我们可以舍弃命令的输出和错误输出,命令如下:
$ command >/dev/null 2>&1
或简写成:
$ command &>/dev/null
相应的标准输入输出描述符示意图如下:
5. 重定向文件内容作为命令的输入
$ command <file
这里, Bash 在执行命令前,试图打开 file 文件并可读。若打开文件失败,命令失败退出。若打开读取文件成功,将使用打开的文件描述符作为命令的标准输入描述符(stdin 号 0)。
上述动作完成后的标准输入输出描述符表示意图如下:
下面是个例子,假定你想从 file 中读取其第1行赋值给变量,命令如下:
$ read -r line < file
Bash 的内建命令 read
从标准输入读取单行数据。 使用输入重定向操作符 < 使它从 file 文件中读取第1行数据。
6. 重定向多行文本到命令的输入
$ command <<EOL
>你
>多行
>文本
>输入
>到这儿
>EOL不是唯一文字
> EOL
>EOL
这里,我们使用 即入文档(here-document) 重定向操作符 "<<MARKER" 的功能。这个操作指示 bash 从标准输入(stdin 0)读取多行输入,直到某行(最后一行)只包含 MARKER 且无前导空白即退出输入。最后一行的终止输入标志不会附加到输入中。将最终的多行输入给命令。
下面是个一般的例子。假设你拷贝了一堆的网上的网址(URLs)在系统剪贴板里,你想去掉所有的前缀 http:// ,快速的单行命令如下:
$ sed 's|http://||' <<EOL
http://url1.com
http://url2.com
http://url3.com
EOL
这里使用即入文档重定向符,将多行网址记录输入给 sed
命令,"sed" 命令使用正则表达式将所有行记录中的 http:// 删除。
以上例子输出:
url1.com
url2.com
url3.com
7. 重定向单行字符串文本到命令输入
$ command <<< "foo bar baz"
举个例子,假如你想系统剪贴板里的文本当作某个命令的输入(文本是命令的参数或选项),可能的办法是:
$ echo "粘帖剪贴板内容" | command
现在你可以使用下面命令:
$ command <<< "粘帖剪贴板内容"
当我学会这个技巧,它改变了我的人生!
8. 重定向所有的错误输出到一个文件
$ exec 2>file
$ command1
$ command2
$ ...
上述第一个命令行使用了 Bash 内建命令 exec
的功能,如果使用它重定向了标准输入输出(演示中是 2 号标准输出 stderr ),它在本 shell 中永久有效!除非你再次修改它或退出这个 shell 。
例子中,使用 exec 2>file
命令将 2 号标准输出(stderr)重定向到 file 文件。之后,在这个 shell 环境里所有命令的标准错误输出都重定向到 file 文件中。这是非常有用的一个技巧。当你想把所有命令或脚本中的运行记录到一个日志文件里,而又不想在每条命令中都繁琐地输入重定向操作。
概括地讲,exec
命令的主要功能是不创建子进程地调用一个 bash 命令或脚本并执行,若命令行中指定了命令或脚本,当前 shell 将被替换。我们演示的命令,在 exec
后并未给出任何命令,这仅仅利用了 exec
的执行重定向的功能,并无 shell 被替换。(译注:个人觉得 exec 是个较分裂的命令。推荐参考这个 链接 中对 exec 命令的解释。或直接看这个 AskUbuntu 中的回答)
9. 创建用户的文件描述符做为自定义的输入描述符
$ exec 3<file
这里,我们再次使用 exec
命令进行重定向的设置,指定 3<file
的意思是打开 file 文件可读取,并将其分配给当前 shell 的 3 号输入文件描述符。当前 shell 的输入输出文件描述符示意图如下:
现在就可以从3号输入文件描述符读取,如下命令:
$ read -u 3 line
上面的命令从 3 号输入文件描述符(重定向到 file 文件)中读取。
或用常规命令,诸如 grep
操作3号输入文件描述符:
$ grep "foo" <&3
这里,3号输入文件描述符通过重定向代替了 grep 命令的默认 stdin 输入。一定要记住,资源有限,故使用完用户自打开的文件描述符后,要及时关闭它,释放描述符号。可以再次使用。
使用完3号文件描述符后,可以关闭它,使用如下命令:
$ exec 3>&-
这里似乎3号文件描述符被重定向给 &- 实际上,&- 就是 关闭这个文件描述符 的一种语法。
10. 创建用户的文件描述符做为自定义的输出描述符
$ exec 4>file
这里,简单地指示 bash 打开可写 file 文件,并将其文件描述符重定向成为4号输出描述符。当前 shell 的输入输出文件描述符示意图如下:
正如你在上图所见,输入输出文件描述符并未按顺序来,用户可自由指定 0 只 255 之间的数字做为自定义打开的文件描述符号。
现在,简单往4号输出文件描述符中写入:
$ echo "foo" >&4
同样,可以关闭4号输出文件描述符:
$ exec 4>&-
学会使用自定义输入输出文件描述符,一切都是那么简单!
11. 打开文件用于读写
$ exec 3<>file
这里使用 bash 的菱形操作符 <>
,菱形操作符打开 file 文件用于读写。
所以,可以执行如下例子:
$ echo "foo bar" > file # 将字符串 "foo bar" 写入 file 文件。
$ exec 5<> file # 以读写方式打开 file 文件并重定向到5号描述符
$ read -n 3 var <&5 # 从5号输入输出描述符中读取前3个字符。
$ echo $var
上面最后命令将输出 "foo" ,只读出前3个字符。
也可写一些内容到 file 文件:
$ echo -n + >&5 # 在文件中第4字符位置写入 "+"
$ exec 5>&- # 关闭5号文件描述符
$ cat file
上面会输出 foo+bar 。(译注:实践发现以永久重定向文件描述符读写文件,会保持读写位置)
12. 多个命令输出重定向到文件
$ (command1; command2) >file
上面例示使用 (commands)
运行命令操作,其中 bash 会将 ()
中的命令在一个创建的子进程中运行。
所以这里的 command1
和 command2
运行在当前 shell 的子进程,同时,bash 将他们的输出重定向到 file 文件。
13. 通过文件 shell 之间传递命令执行
打开2个 shell 模拟终端,在第1个 shell 中,输入命令:
$ mkfifo fifo
$ exec < fifo
在第2个 shell 中,输入命令:
$ exec 3> fifo; echo 'echo test' >&3
现在看第1个 shell ,发现 echo test
命令执行输出在第1个 shell 里。你可以在第2个 shell 中发送命令字符串给3号描述符的方式给第1个 shell 发送命令。
下面讲解它是如何做到的。
在 shell 1 中,使用 mkfifo
创建 命名管道 -- fifo 。一个命名管道(也称为 FIFO)性质与一般的管道相同,除了它是通过系统文件系统访问之外(创建命名管道将会在当前目录下创建一个以命名管道名命名的文件,这个文件第一个属性为 p 表示它为一个 管道(pipe),并且文件大小始终显示为 0)。它可供多进程读写(可供进程间通讯)。当进程间通过 FIFO --命名管道--交换数据时,系统内核并不会把数据写入文件存储系统。因此,命名管道文件大小永远为 0 。仅仅把文件系统中的文件名做为进程引用它的一个名称罢了。
下一命令 exec < fifo
重定向 shell 1 的输入为 fifo 。
接着,shell 2 重定向这个命名管道做为用户输出文件描述符,并分配号为 3 。然后给 3 号输出发送字符串 echo test
,这将传给 fifo 文件。
因此,shell 1 连接到 fifo 的标准输入进入 shell 1 命令行并执行!很容易吧!
(译注:原理很简单,自己开两个shell 去实践练习一下。别的不多说,只提醒一点:当 shell 1 把自己的标准输入重定向成命名管道之后,它就不能接受它自己终端的输入了。如何恢复它回到原始的输入?2个办法,1.是重定向前备份。2.是使用它原始的名称恢复,提示:输入仅可用 /dev/tty 。至于怎样让它执行命令?自己想想,你棒棒哒!)
14. 通过 bash 访问网站
$ exec 3<>/dev/tcp/www.bing.com/80
$ echo -e "GET / HTTP/1.1\n\n" >&3
$ cat <&3
Bash 处理 /dev/tcp/host/port 作为特殊文件。它不需要在你的文件系统中存在。这个只为 Bash 通过它打开指定主机的网络接口。
以上例子,首先打开可读写3号输入输出文件描述符指向 /dev/tcp/www.bing.com/80 ,它将链接到 www.bing.com 网站的端口 80 。
下一步,向3号文件描述符写入 'GET / HTTP/1.1\n\n' (发送HTTP请求),然后使用 cat
命令简单读取3号文件描述符的内容。
类似地,你可以通过 /dev/udp/host/port 创建特殊文件用于 UDP 连接。
使用 /dev/tcp/host/port 的方法,你甚至可以在 Bash 中写出端口扫描的命令或脚本!
(译注:原文示例使用的是谷歌,我这里换成了必应。实验了一下,可能由于现在网站都使用 SSL 的缘故,第一次会获得一个包含错误提示的 HTTP 响应内容,连接就关闭了)
15. 当重定向输出时阻止写入已有文件
$ set -o noclobber
上面的命令打开当前 shell 的 noclobber 选项。这个选项阻止当前 shell 使用重定向 '>' 操作覆盖写入已有的文件。
如果你输出重定向的文件是一个已有文件,将会得到一个错误提示:
$ > exFile
$ echo test > exFile
bash: exFile: cannot overwrite existing file
#bash: exFile: 不能覆写已有文件
如果你完全确定就是要覆盖写入已有文件,可以使用 >| 重定向符:
$ echo test >| exFile
$ cat exFile
test
这个操作符成功超越 noclobber 选项。
16. 将输入重定向到一个文件和输出到标准输出
$ command | tee file
这个 tee
命令超级方便,虽然它不是 bash 的内建命令但很常用。它能把收到的输入流输出到标准输出和一个文件中。
如上例子,它将 command
命令的输出分别输出到 shell 屏幕和一个文件。
下面是它工作原理示意图:
17. 将一个处理进程(命令)的输出重定向到另一个处理进程(命令)的输入
$ command1 | command2
这是简单的管道。我确定每个人都熟悉它。我放它到这里只是为了教程的完整。仅仅提醒你,管道 的本质就是将命令 command1
的 输出 重定向到 command2
命令的 输入 。
可以用图示意如下:
上图可见,所有到达 command1 标准输出(1 stdout)的内容都被重定向到了 command2 的标准输入(0 stdin)。
更进一步请参考手册命令 man 2 pipe
.
18. 发送一个命令的标准输出和标准错误输出到另一命令进程
$ command1 |& command2
这个操作符在 bash 4.0 版本后出现。 |&
重定向操作符通过管道将 command1
命令的标准输出和标准错误输出都发到 command2
命令的标准输入。
最新的 bash 4.0 版 的新功能未广泛普及前,旧的,方便的方法是:
$ command1 2>&1 | command2
下面是标准输入/输出描述符 的变化示意图:
前面的操作先将 command1 的 stderr(2) 重定向到 stdout(1) ,然后通过管道将标准输出重定向到 command2 的标准输入 stdin(0) 。
19. 为创建的文件描述符赋名
$ exec {filew}>output_file
#译注:引用命名文件描述符,使用 &$ 如下命令:
$ echo test >&$filew #译者加的命令
命名文件描述符 是 bash 4.1 版后的功能特性。以 {varname}>output_file
定义了名为 varname 的输出文件描述符到指定文件。你可以通过其名称、文件描述符号正常使用它。Bash 在内部会给它分配一个空闲的文件描述符号。(译注:这个命令很容易和临时重定向到一个文件混淆!关于如何用其名称引用它,我写到上面的代码注释里。如何找到其文件描述符号,参见译注1.)
20. 重定向操作的顺序
你可以把重定向操作放到命令行的任何位置。看看下面3个例子,它们效果一样:
$ echo hello >/tmp/example
$ echo >/tmp/example hello
$ >/tmp/example echo hello
喜欢上了 bash !
21. 交换标准 stdout 和 stderr
$ command 3>&1 1>&2 2>&3
这里,首先将 stdout(&1) 复制一个副本 &3 --3号文件描述符-- ,再使 stdout(&1) 成为 stderr(&2) -- 2号文件描述符-- 的副本,最后使 stderr(&2) 成为 &3 的副本。这样将 stdout 和 stderr 进行了交换。
让我们用图示展示每步过程。下面是命令开始时的文件描述符状态图示:
然后,3>&1
重定向操作符指示,创建 3号输出文件描述符指向跟 &1 相同:
下一个1>&2
重定向操作符指示,将 1号标准输出文件描述符指向跟 &2 相同:
下一个2>&3
重定向操作符指示,将 2号标准输出文件描述符指向跟 &3 相同(即原始的 &1):
如果想关闭不再有用的好人 &3 --3号文件描述符-- ,见如下命令:
$ command 3>&1 1>&2 2>&3 3>&-
之后的文件描述符表示意如下:
如你所见,文件描述符 1号 和 2号 已经交换。
22. 重定向 stdout 到一个进程,stderr 到另一进程
$ command > >(stdout_cmd) 2> >(stderr_cmd)
这行命令使用了重定向命令替换展开操作符 >()
。它将会运行 () 中的命令。而其标准输入通过匿名管道连接到了 command
的标准输出。接着下一个 >()
操作符将其标准输入连接到了 command
的标准错误输出。
对于上面的例子,第一个命令替换 >(stdout_cmd)
可能使 bash 返回 /dev/fd/60
文件描述符。同时,第二个命令替换 >(stderr_cmd)
可能使 bash 返回 /dev/fd/61
文件描述符。这2个文件描述符由 bash 实时创建为等待读取的命名管道。它们都等待某些命令进程往里写,以便它们读取。
所以,上述命令展开后可能是这样:
$ command > /dev/fd/60 2> /dev/fd/61
现在可看得清楚些, command 的 stdout 重定向到 /dev/fd/60 , stderr 重定向到 /dev/fd/61 。
当 command 输出,内部进程 'stdout_cmd' 的命令执行将接受。当 command 的错误输出,内部进程 'stderr_cmd' 的命令执行将接受。
23. 找出每个管道命令的退出码
让我们看一下几个命令用管道串起来的例子,如下命令:
$ cmd1 | cmd2 | cmd3 | cmd4
你想找出这里每个命令的退出状态码,该如何做?有没有一个简便的方法获取每个命令的退出状态码,而不是 bash 简单给出的最后一条命令的退出状态码。
Bash 的开发者想到了这点,他们加入了一个名为 'PIPESTATUS' 的数组变量来保留管道命令流中每个命令的运行退出状态码。
数组变量 PIPESTATUS 中的每个数字都对应于相应位置命令的退出状态码。下面是个例子:
$ echo 'men are cool' | grep 'moo' | sed 's/o/x/' | awk '{ print $1 }'
$ echo ${PIPESTATUS[@]}
0 1 0 0
上面例子中,命令 grep 'moo'
失败,因此数组变量 PIPESTATUS 中的第2个数为 1 。
建议
建议研究 bash 高手们的百科 演示重定向教程 和 bash 版本进化.
欢迎指正
享受文中所说的方法和技巧使用的乐趣吧,并且让我知道您的想法。也许我漏掉了什么,非常乐意收到您的指正。
----------------------------------------
----------------------------------------
译注
1. 如何发现当前 bash 的所有文件描述符
以下内容,译者受网文 Linux: Find All File Descriptors Used By a Process 启发,针对在 bash 中发现其所有文件描述符的任务进行创作。
一、找到当前 bash 进程 ID -- PID
方法1:使用查看进程命令,如 ps 命令
语法:
ps aux | grep [程序名称]
ps 命令,参考本站wiki ps 命令(查看进程) 。
对于我们的情况,程序名称 是 bash ,命令如下:
$ ps aux | grep bash
可能的输出如下:
aman 7146 0.0 0.2 30748 5728 pts/4 Ss 09:42 0:00 bash
aman 7978 0.0 0.2 24432 5516 pts/18 Ss+ 13:56 0:00 bash
aman 8022 0.0 0.0 15964 928 pts/4 S+ 14:10 0:00 grep --color=auto bash
这里,我专门打开了2个 shell ,哪个是我们当前的 shell 呢?方法很多,使用 tty
命令找出当前的 tty 与上面的输出对比。找到本 shell 的 PID 是 7146 。
方法2:使用 pidof 命令
语法:
pidof [程序名称]
这个方法不适用同时开了多个 shell 的例子,但只有一个 shell 时会很简单,如下命令:
$ pidof bash
7146
二、根据 bash 的 PID 找到其使用的所有文件描述符
方法1:查看 /proc/pid/fd 目录
如下所示命令及输出:
$ ls -l /proc/7146/fd
total 0
lrwx------ 1 aman aman 64 12月 27 09:42 0 -> /dev/pts/4
l-wx------ 1 aman aman 64 12月 27 09:42 1 -> /dev/pts/4
l-wx------ 1 aman aman 64 12月 27 09:42 10 -> /home/aman/test/nFD
lrwx------ 1 aman aman 64 12月 27 09:42 2 -> /dev/pts/4
lrwx------ 1 aman aman 64 12月 27 12:02 255 -> /dev/pts/4
我之前在这个 shell 下,使用 $ exec {FD1}> nFD
命令创建了一个永久命名文件描述符重定向到了当前目录下的 nFD 文件。在这里我们看见 bash 内部给它分配了文件描述符号 10 。这样,你在重定向输出时就即可使用 &$FD1 或 &10 都会输出到 nFD 文件。
我的运行示意如下:
$ echo 'line 1' >&10
$ echo 'line 2' >&$FD1 #这行命令与上行输出到相同目的地
$ cat nFD
line 1
line 2
方法2:使用 lsof 命令
语法:
lsof -a -p {输入PID}
lsof 命令,参考 ’ lsof command ' 。我的命令示意如下:
$ lsof -a -p 7146
输出:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 7146 aman cwd DIR 8,5 4096 178864 /home/aman/test
bash 7146 aman rtd DIR 8,5 4096 2 /
bash 7146 aman txt REG 8,5 1037528 134435 /bin/bash
bash 7146 aman mem REG 8,5 101200 265464 /lib/x86_64-linux-gnu/libresolv-2.23.so
...
...
...
bash 7146 aman 0u CHR 136,4 0t0 7 /dev/pts/4
bash 7146 aman 1w CHR 136,4 0t0 7 /dev/pts/4
bash 7146 aman 2u CHR 136,4 0t0 7 /dev/pts/4
bash 7146 aman 10w REG 8,5 16 178735 /home/aman/test/nFD
bash 7146 aman 255u CHR 136,4 0t0 7 /dev/pts/4
见上面输出倒数第二行,可知 nFD 文件的重定向文件描述符号为 10 。
本作品采用《CC 协议》,转载必须注明作者和本文链接