有没有办法关闭所有打开的文件描述符,而无需事先明确列出它们?
答案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
命令0
或1
您要关闭的任何文件描述符)。
笔记:另外使用 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
.