关闭 bash 中的所有文件描述符

Lor*_*one 14 shell bash file-descriptors

有没有办法关闭所有打开的文件描述符,而无需事先明确列出它们?

Gra*_*eme 18

从字面上回答,关闭所有打开的文件描述符bash

for fd in $(ls /proc/$$/fd); do
  eval "exec $fd>&-"
done
Run Code Online (Sandbox Code Playgroud)

然而,这真的不是一个好主意,因为它会关闭 shell 输入和输出所需的基本文件描述符。如果您这样做,您运行的所有程序都不会在终端上显示其输出(除非它们tty直接写入设备)。如果事实在我的测试中关闭stdin( exec 0>&-) 只会导致交互式 shell 退出。

您实际上可能想要做的是关闭所有不属于 shell 基本操作的文件描述符。它们是 0 代表stdin、1 代表stdout和 2 代表stderr。最重要的是,默认情况下,某些 shell 似乎还打开了其他文件描述符。bash例如,在 中,您有 255 个(也用于终端 I/O),而在dash我中有 10 个,它指向/dev/tty而不是终端正在使用的特定tty/pts设备。要关闭除 0、1、2 和 255 之外的所有内容bash

for fd in $(ls /proc/$$/fd); do
  case "$fd" in
    0|1|2|255)
      ;;
    *)
      eval "exec $fd>&-"
      ;;
  esac
done
Run Code Online (Sandbox Code Playgroud)

另请注意,eval重定向包含在变量中的文件描述符时需要这样做,否则bash将扩展变量但将其视为命令的一部分(在这种情况下,它将尝试exec命令01您尝试关闭的任何文件描述符)。

注意:同样使用 glob 而不是ls(eg /proc/$$/fd/*) 似乎会为 glob 打开一个额外的文件描述符,所以ls这里似乎是最好的解决方案。

更新

有关可移植性的更多信息/proc/$$/fd,请参阅文件描述符链接的可移植性。如果/proc/$$/fd不可用,则替换$(ls /proc/$$/fd), using lsof(如果可用)将是$(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)

  • @chepner 如果你说`/proc/PID/fd` 不是很便携,那你是对的。但是说`/proc` 只在Linux 下可用是**不**的说法。 (4认同)

小智 6

在 Bash 的最新版本(4.1 及更高版本,2009 年及更高版本)中,您可以使用 shell 变量指定要关闭的文件描述符:

for fd in $(ls /proc/$$/fd/); do
    [ $fd -gt 2 ] && exec {fd}<&-
done
Run Code Online (Sandbox Code Playgroud)

该功能已经在 Korn shell 中(自 1993 年以来?),但显然需要一些时间才能进入 Bash。