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

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

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

答案1

从字面上回答,关闭全部打开文件描述符bash

for fd in $(ls /proc/$$/fd); do
  eval "exec $fd>&-"
done

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

您实际上可能想做的是关闭所有不属于 shell 基本操作的文件描述符。这些是 0 stdin、 1stdout和 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

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

笔记:另外使用 glob 而不是ls(eg /proc/$$/fd/*) 似乎会为 glob 打开一个额外的文件描述符,因此ls似乎是这里的最佳解决方案。

更新

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

答案2

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

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

该功能已经存在于 Korn shell 中(从 1993 年开始?),但显然花了一些时间才进入 Bash。

答案3

清除除当前 shell 的 i/o/e 之外的所有文件描述符,但也不包括作为参数提供的文件描述符

clear_fds() {
for fd in $(compgen -G "/proc/$BASHPID/fd/*"); do
    fd=${fd/*\/}
        if [[ ! " $* " =~ " ${fd} " ]]; then
            case "$fd" in
                0|1|2|255)
                ;;
                *)
                    eval "exec $fd>&-"
                    ;;
            esac
        fi
done
}

答案4

不可以。内核一次只能关闭一个 FD,而 bash 没有针对 FD 的“组命令”。

for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done

测试后删除echo"

如果这不是为了 shell 本身而是为了要运行的命令,那么您可以使用nohup.

相关内容