![文件描述符 3 在 vgcfgbackup 调用时泄漏。父 PID:bash](https://linux22.com/image/1591655/%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6%203%20%E5%9C%A8%20vgcfgbackup%20%E8%B0%83%E7%94%A8%E6%97%B6%E6%B3%84%E6%BC%8F%E3%80%82%E7%88%B6%20PID%EF%BC%9Abash.png)
我正在使用 bash 脚本对带有 lvm 的 ubuntu 机器进行备份,然后将其上传到 google drive,脚本每天通过 cron 运行,没有问题,但日志文件包含以下错误:
File descriptor 3 (/root/borg.sh) leaked on lvcreate invocation. Parent PID 27827: bash
这个错误到底是什么意思?它与 lvcreate/vgcfgbackup 或 bash 脚本本身有关吗?我找不到任何有用的信息,只有“调用时泄露”可能是无害的。
在 lvcreate 和 vgcfgbackup 中添加了 -vvv 的完整日志: http://dpaste.com/3FYVAC0
bash 脚本: http://dpaste.com/30NV1ZH
答案1
从man lvm
:
在调用时,lvm 要求只有标准文件描述符 stdin、stdout 和 stderr 可用。如果发现其他文件描述符,则关闭它们并发出有关泄漏的警告消息。可以通过设置环境变量 LVM_SUPPRESS_FD_WARNINGS 来抑制此警告。
您可能在脚本中使用了文件描述符 3。LVM_SUPPRESS_FD_WARNINGS
在调用之前,请在脚本中导出环境变量lvcreate
。
答案2
我的看法:
是的!我经常在cron
工作中看到这种情况:crond
(cron守护进程)运行他的脚本pipes
为了在需要的时候开车去sendmail
,他们打开了一些不寻常的文件描述符(输入/输出馈线)。
对这条消息感到厌倦,我做了一些测试...所以有一些意见/解决方案:
1. 使用LVM_SUPPRESS_FD_WARNINGS
环境变量
作为伯尼的正确答案建议,最简单的解决方案是设置环境变量:LVM_SUPPRESS_FD_WARNINGS
作为
LVM_SUPPRESS_FD_WARNINGS=1 lvs
LVM_SUPPRESS_FD_WARNINGS=1 lvcreate ...
或者简单来说:
export LVM_SUPPRESS_FD_WARNINGS=1
lvs
lvcreate ...
但是,有一种方法可以在运行它们之前满足 LVM 的要求!
2. 将 LVM 环境限制为仅需要文件描述符:
然后,为了更好地理解:
创建一些有用的 FD
exec {dummyFd}<> <(: -)
适合read
用作内置睡眠,样本替换为sleep 1.5
:
read -ru $dummyFd -t 1.5 _
好吧,如果我lvs
:
# lvs >/dev/null
File descriptor 10 (pipe:[194609045]) leaked on lvs invocation. Parent PID 849375: -bash
尝试lvs
通过关闭来无错误地运行不需要的FD
在子 shell 中:
(exec {dummyFd}<&-;lvs) >/dev/null
将会完成这项工作!
在一个读环形:
如何将 LVS 输出存储到有用的变量中?例如,我这样做是为了存储快照使用情况变成关联数组:
declare -Ai lvStat='()'
while read -r lv vg attr size orig prct; do
case $attr in
s* ) printf -v prct %.2f ${prct%\%}
lvStat[$lv/$vg]=${prct/.} ;;
esac
done < <( exec {dummyFd}>&-; lvs )
我使用整数来存储带有两位小数的百分比值,只需删除小数点即可。所以我必须将测试值乘以 100:
for vol in "${!lvStat[@]}"; do
(( ${lvStat["$vol"]} > 8000 )) &&
printf 'Volume %s > 80%%: %8.2f%%\n' "$vol" \
${lvStat["$vol"]::-2}.${lvStat["$vol"]: -2}
done
整体包装全部关闭不需要的FD
:
以下是一点包装器关闭所有打开的 FD 的函数,但不会0
STDIN
,1
STDOUT
和2
STDERR
:
closeFdWrapper4Lv()(
allFileDescriptors=(/dev/fd/*)
for fileDescriptor in ${allFileDescriptors[@]##*/}; do
case $fileDescriptor in
0|1|2 ) ;;
* ) exec {fileDescriptor}>&- ;;
esac
done
"$@"
)
关心括号围绕功能而不是常规大括号!!!
然后你可以运行:
closeFdWrapper4Lv lvs
closeFdWrapper4Lv lvcreate ...
仍然可以使用你打开的文件描述符:
read -ru $dummyFd -t 1.5 _