Bash中文件描述符的详细介绍

 更新时间:2018年04月22日 10:41:11   作者:始于珞尘  
这篇文章主要给大家介绍了关于Bash中文件描述符的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

前言

Linux将所有内核对象当做文件来处理,系统用一个size_t类型来表示一个文件对象,比如对于文件描述符0就表示系统的标准输入设备STDIN,通常情况下STDIN的值为键盘,如read命令就默认从STDIN读取数据,当然STDIN的值是可以改变的,比如将其改成其他文件,这样的话想read等命令就会默认从相应的文件读取数据了。

简单地说,一个文件描述符可以和一个文件挂钩,一旦挂钩就可以通过取地址运算符&获得该文件的句柄,比如&0就可以获得STDIN设备在内存中的句柄(设备在系统中也被当做文件处理),可以这样理解,如果是一个shell中的普通变量var,可以通过$var的形式获得该变量所代表的值,而对于一个文件描述符fd,则可以通过&fd的形式获得文件描述符指向的文件的句柄,而这个句柄可以简单地理解成该文件的路径。

在 Shell 编程里经常会用到重定向操作, 它本质上是对文件描述符进行操作, 本文会对 Shell 脚本里的文件描述符做一个详细的介绍.

默认标准文件描述符

每个进程启动时默认都会有三个标准的文件描述符:

  • stdin 0 号描述符, 代表输入设备, 进程从它读入数据;
  • stdout 1 号描述符, 进程往其中写入数据;
  • stderr 2 号描述符, 进程会往其中写入错误信息;

这三个描述符默认是对应同一个 tty 设备, 这样我们便可以在终端中输入数据和获取进程的输出.

默认的文件描述符也是可以被替换的, 例如我们可以替换掉 stdout 到一个文件, 这样命令的输出就不是打印到终端, 而是被输出到文件中:

在上面的 demo 中, 我们先是通过 exec 1 > /tmp/stdout 把 stdout 指向了文件 /tmp/stdout, 紧接着我们执行了两条命令 ls 和 pwd, 可以看到此时终端已经没有了命令的输出. 当我们通过 exec 1 >&2 恢复 stdout 后, 可以发现文件 /tmp/stdout 里存储了之前命令的输出.

其中 exec 是一个 bash 内置命令, 不同于在终端中执行命令时会 fork 一个子进程, 通过 exec 执行的命令会直接修改当前的 shell 进程, 可以通过它执行命令来修改当前 shell 的 context.

如果你想使坏的话可以在别人的 ~/.bashrc 里加入 exec 1 > /tmp/stdout, 这样新开的所有的终端窗口里都看不到命令的输出, 要是因此被打概不负责 :) .

文件描述符的操作

Shell 中对文件描述符的操作由三部分组成: (Left, Operation, Right):

  • Left 可以是 0-9 的数字, 代表第 n 号文件描述符;
         Left 还可以为 &, 表示同时操作 stdout 和 stderr
  • Right 可以是文件名或 0-9 的数字, 当 Right 是数字时必须要加上 & 符号, 表示引用第 n 号文件描述符;
         Right 还可以为 &-, 此时表示关闭 Left 描述符, 例如 2<&- 表示关闭 stderr;
  • Operation 可以为 < 或 >;
         为 < 时表示以读模式复制 Right 到 Left, 此时如果没有指定 Left 的话, 则为默认值 0;
         当为 > 表示以写模式复制 Right 到 Left, 此时如果没有指定 Left 的话, 则为默认值 1;
         Operation 和 Left 之间不能有空格;
         当 Right 为文件名时, Operation 和 Right 可以有空格, 否则也不能有空格;

当存在多个文件描述符的操作时, 会按照从左往右的顺序依次执行. 例如通过命令 cmd 3>&1 1>&2 2>&3 3>&- 就可以交换 stdin 和 stdout.

我们通过下面的例子来验证上面的文件描述符交换是否生效:

  • 首先把默认的 stderr 重定向到文件 /tmp/stderr 中, 这样在终端中就不会看到错误输出了;
  • 当交换完 stderr 和 stdout 后, 我们就可以在 /tmp/stderr 文件中看到命令的正常输出了;

让我们来开始实验吧:

➜ test exec 2> /tmp/stderr
➜ test ls
a.txt
➜ test ls 3>&1 1>&2 2>&3 3>&-
➜ test cat /tmp/stderr
a.txt

和我们的预期时一致的!

一些示例

用文件重载 stdin :

➜ test cat 0< a.txt
hello
➜ test cat < a.txt # same with last command
hello

把 stderr 和 stdout 都过滤掉

ls not_exist 1> /dev/zero 2>&1
# another way
ls not_exist &> /dev/zero

处理上一个命令的错误输出:

➜ blog git:(hexo) ls not_exist 2>&1 | sed 's/not_exist/error/g'
ls: error: No such file or directory
# another way
➜ blog git:(hexo) ls not_exist |& sed 's/not_exist/error/g'
ls: error: No such file or directory

把标准输出转入到错误输出上: echo hello 1>&2

Process Substitution

在 bash 中提供了两个特殊的操作, 它们都可以被直接当成文件名使用:

  • <(cmd) : 可以看作时一个可读文件, cmd 命令的输出是这个文件的内容;
  • >(cmd) : 可以看作时一个可写文件, cmd 会接受输入并进行处理;

示例

利用 <(cmd) 来验证一对公私钥是否匹配:

➜ blog git:(hexo) diff <(ssh-keygen -y -e -f ~/.ssh/id_rsa) <(ssh-keygen -y -e -f ~/.ssh/id_rsa.pub)
➜ blog git:(hexo)

利用 >(cmd) 来对错误信息进行处理, 同时保证错 stderr 信息不回变成 stdout:

➜ blog git:(hexo) ls not_exist 2> >(sed 's/not_exist/keep_error/g')
ls: keep_error: No such file or directory
➜ blog git:(hexo)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

References

相关文章

  • Linux yum 命令安装mysql8.0的教程详解

    Linux yum 命令安装mysql8.0的教程详解

    这篇文章主要介绍了Linux yum 命令安装mysql8.0的教程,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • Linux VPS安全设置之三:使用DDOS deflate抵御少量DDOS攻击

    Linux VPS安全设置之三:使用DDOS deflate抵御少量DDOS攻击

    这篇文章主要介绍了Linux VPS安全设置之三:使用DDOS deflate抵御少量DDOS攻击,需要的朋友可以参考下
    2016-10-10
  • Linux系统使用用户密钥ssh主机访问

    Linux系统使用用户密钥ssh主机访问

    这篇文章主要介绍了Linux系统使用用户密钥ssh主机访问,它在安全上完全大于直接输入root 的密码,有需要的可以了解一下。
    2016-10-10
  • linux安装单机版HBase的详细过程

    linux安装单机版HBase的详细过程

    这篇文章主要介绍了linux安装单机版HBase的详细过程,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-07-07
  • CentOS6.6安装CloudStack4.8

    CentOS6.6安装CloudStack4.8

    CloudStack是一个开源的具有高可用性及扩展性的云计算平台。接下来通过本文给大家介绍CentOS6.6安装CloudStack4.8的方法,感兴趣的朋友一起看看吧
    2016-10-10
  • Linux服务器搭建nvidia-docker环境过程详解

    Linux服务器搭建nvidia-docker环境过程详解

    这篇文章主要介绍了Linux服务器搭建nvidia-docker环境过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • vscode连接远程Linux服务器及免密登陆的详细步骤

    vscode连接远程Linux服务器及免密登陆的详细步骤

    这篇文章主要介绍了vscode连接远程Linux服务器及免密登陆,本文分步骤给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • Linux tar命令使用列子

    Linux tar命令使用列子

    对许多用户来说,在DOS和Windows环境下利用工具软件WinZip、ARJ等压缩或解压文件是比较容易的事。但是,在Linux中如何对文件进行压缩与解压呢?
    2008-06-06
  • telnet nc命令返回“连接失败”问题及解决

    telnet nc命令返回“连接失败”问题及解决

    当使用nc或telnet命令测试端口连接时,如果返回“connection refused”错误,通常可能是因为:1. 目标端口未被监听,即没有服务在运行于该端口;2. 防火墙策略阻止了该端口的连接;3. 目标主机配置了只允许特定IP或子网的连接,这些情况都会导致连接尝试失败
    2024-10-10
  • environments was not found on the java.library.path 问题的解决方法

    environments was not found on the java.library.path 问题的解决方法

    The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path 问题的解决方法,需要的朋友可以参考下
    2016-08-08

最新评论