【发布时间】:2019-09-05 18:23:26
【问题描述】:
我一直在尝试理解我们在工作中使用的一些脚本出现的问题。
为了生成我们的许多脚本日志,我们利用exec 命令和文件重定向将脚本的所有输出打印到终端和日志文件。有时,对于不需要向用户显示的信息,我们会直接重定向到日志文件。
当我们打印执行期间发生的错误数量时,我们看到的问题发生在文件输出的最后一行:文本没有打印到文件中。 em>
为了诊断问题,我编写了我们的生产脚本 (script1.bash) 和测试脚本 (script2.bash) 的简化版本来尝试梳理问题。
script1.bash
#!/bin/bash
log_name="${USER}_`date +"%Y%m%d-%H%M%S"`_${HOST}_${1}.log"
log="/tmp/${log_name}"
log_tmp="/tmp/temp_logs"
err_count=0
finish()
{
local ecode=0
if [ $# -eq 1 ]; then
ecode=${1}
fi
# This is the problem line
echo "Error Count: ${err_count}" >> "${log}"
mvlog
local success=$?
exec 1>&3 2>&4
if [ ${success} -ne 0 ]; then
echo ""
echo "WARNING: Failed to save log file to ${log_tmp}"
echo ""
ecode=$((ecode+1))
fi
exit ${ecode}
}
mvlog()
{
local ecode=1
if [ ! -d "${log_tmp}" ]; then
mkdir -p "${log_tmp}"
chmod 775 "${log_tmp}"
fi
if [ -d "${log_tmp}" ]; then
rsync -pt --bwlimit=4096 "${log}" "${log_tmp}/${log_name}" 2> /dev/null
[ $? -eq 0 ] && ecode=0
if [ ${ecode} -eq 0 ]; then
rm -f "${log}"
fi
fi
}
exec 3>&1 4>&2 >(tee "${log}") 2>&1
ecode=0
echo
echo "Some text"
echo
finish ${ecode}
script2.bash
#!/bin/bash
runs=10000
logdir="/tmp/temp_logs"
if [ -d "${logdir}" ]; then
rm -rf "${logdir}"
fi
for i in $(seq 1 ${runs}); do
echo "Conducting run #${i}/${runs}..."
${HOME}/bin/script1.bash ${i}
done
echo "Scanning logs from runs..."
total_count=`find "${logdir}" -type f -name "*.log*" | wc -l`
missing_count=`grep -L 'Error Count:' ${logdir}/*.log* | grep -c /`
echo "Number of runs performed: ${runs}"
echo "Number of log files generated: ${total_count}"
echo "Number of log files missing text: ${missing_count}"
我的第一个测试表明大约 1% 的时间该行没有写入日志文件。然后我尝试了几种不同的方法来处理这行输出。
- 回声和等待
echo "Error Count: ${err_count}" >> "${log}"
wait
- 替代打印方法
printf "Error Count: %d\n" ${err_count} >> "${log}"
- 无显式文件重定向
echo "Error Count: ${err_count}"
- 回声和睡眠
echo "Error Count: ${err_count}" >> "${log}"
sleep 0.2
其中,#1 和#2 的失败率分别为 1%,而#4 的失败率达到了惊人的 99%。 #3 是唯一失败率为 0% 的方法。
在这一点上,我不知道为什么会发生这种行为,所以我在这里向大师们寻求任何见解。
(请注意,简单的解决方案是实现#3,但我想知道为什么会发生这种情况。)
【问题讨论】:
-
顺便说一句,请参阅stackoverflow.com/questions/36313216/… 并可能尝试shellcheck.net
-
>(tee "${log}")看起来像罪魁祸首;它运行一个子进程,在你的脚本退出之前可能会也可能不会被杀死。