如何确定 Bash 当前是否正在使用文件描述符?例如,如果我有一个读取、写入和关闭 fd 3 的脚本,例如
exec 3< <(some command here)
...
cat <&3
exec 3>&-
确保我不会干扰在脚本运行之前可能已设置的描述符的其他用途的最佳方法是什么?我需要把我的整个脚本放在一个子shell中吗?
如何确定 Bash 当前是否正在使用文件描述符?例如,如果我有一个读取、写入和关闭 fd 3 的脚本,例如
exec 3< <(some command here)
...
cat <&3
exec 3>&-
确保我不会干扰在脚本运行之前可能已设置的描述符的其他用途的最佳方法是什么?我需要把我的整个脚本放在一个子shell中吗?
如果您不关心文件描述符是否高于 9,您可以要求 shell 本身提供一个。当然,fd 由自己的 shell 保证是免费的。
自 bash 4.1+ (2009-12-31) {varname} 样式自动文件描述符分配以来可用的功能
$ exec {var}>hellofile
$ echo "$var"
15
$ echo "this is a test" >&${var}
$ cat hellofile
this is a test
$ exec {var}>&- # to close the fd.
事实上,在 linux 中,你可以看到打开的 fds:
$ ls /proc/$$/fd
0 1 2 255
在 purebash
中,您可以使用以下方法查看给定的文件描述符(3
在这种情况下)是否可用:
rco="$(true 2>/dev/null >&3; echo $?)"
rci="$(true 2>/dev/null <&3; echo $?)"
if [[ "${rco}${rci}" = "11" ]] ; then
echo "Cannot read or write fd 3, hence okay to use"
fi
这基本上通过测试您是否可以读取或写入给定的文件句柄来工作。假设您两者都做不到,那么使用它可能是可以的。
在查找第一个免费描述符方面,您可以使用以下内容:
exec 3>/dev/null # Testing, comment out to make
exec 4</dev/null # descriptor available.
found=none
for fd in {0..200}; do
rco="$(true 2>/dev/null >&${fd}; echo $?)"
rci="$(true 2>/dev/null <&${fd}; echo $?)"
[[ "${rco}${rci}" = "11" ]] && found=${fd} && break
done
echo "First free is ${found}"
运行该脚本会5
作为第一个免费描述符提供,但您可以使用这些exec
行来查看如何使较早的可用描述符允许代码片段找到它。
正如评论中所指出的,提供procfs
(/proc
文件系统)的系统有另一种方法可以检测免费描述符。该/proc/PID/fd
目录将包含每个打开文件描述符的条目,如下所示:
pax> ls -1 /proc/$$/fd
0
1
2
255
因此,您可以使用与上述类似的脚本在其中找到一个免费条目:
exec 3>/dev/null # Testing, comment out to make
exec 4</dev/null # descriptor available.
found=none
for fd in {0..200} ; do
[[ ! -e /proc/$$/fd/${fd} ]] && found=${fd} && break
done
echo "First free is ${found}"
请记住,并非所有提供的系统bash
都必须具有procfs
(BDS 和 CygWin 就是示例)。如果那是您的目标操作系统,Linux 应该没问题。
当然,您仍然可以选择将整个 shell 脚本包装成如下内容:
(
# Your current script goes here
)
在这种情况下,文件句柄将保留在这些括号之外,您可以根据需要在其中操作它们。
使用 pre-bash-4.1 语法的另一个答案做了很多不必要的子外壳生成和冗余检查。它还具有最大 FD 数量的任意截止值。
下面的代码应该在不产生子shell的情况下完成这个技巧(ulimit
如果我们想获得一个体面的 FD 号码上限,则可以用于调用)。
fd=2 max=$(ulimit -n)
while ((++fd < max)); do
! true <&$fd && break
done 2>/dev/null && echo $fd
Bad file descriptor
上次循环迭代的错误消息,我们为整个while
循环重定向 stderr。对于那些喜欢单行且没有可用的 Bash-4.1+ 的人:
{ seq 0 255; ls -1 /proc/$$/fd; } | sort -n | uniq -u | head -1
我决定将@paxdiablo 给出的出色答案总结为带有两个辅助函数的单个 shell 函数:
fd_used_sym() {
[ -e "/proc/$$/fd/$1" ]
}
fd_used_rw() {
: 2>/dev/null >&$1 || : 2>/dev/null <&$1
}
fd_free() {
local fd_check
if [ -e "/proc/$$/fd" ]
then
fd_check=fd_used_sym
else
fd_check=fd_used_rw
fi
for n in {0..255}
do
eval $fd_check $n || {
echo "$n"
return
}
done
}
有一些简化——在不丢失主要功能的情况下摆脱辅助功能:
fd_free() {
local fd_check
if [ -e "/proc/$$/fd" ]
then
fd_check='[ -e "/proc/$$/fd/$n" ]'
else
fd_check=': 2>/dev/null >&$n || : 2>/dev/null <&$n'
fi
for n in {0..255}
do
eval $fd_check || {
echo "$n"
return
}
done
}
这两个函数都检查文件描述符的可用性并输出第一个找到的空闲文件描述符的编号。好处如下:
/proc/$$/fd/X
和 R/W 到特定 FD)