使用 echo >> 会产生不一致的结果

Use of echo >> produces inconsistent results

我一直在尝试理解我们在工作中使用的一些脚本中出现的问题。

为了生成我们的许多脚本日志,我们使用 exec 命令和文件重定向将脚本的所有输出打印到终端和日志文件。有时,对于不需要向用户显示的信息,我们会直接重定向到日志文件。

当我们打印执行期间发生的错误数时,我们看到的问题出现在文件输出的最后一行:文本没有打印到文件.

为了诊断问题,我编写了生产脚本的简化版本 (script1.bash) 和测试脚本 (script2.bash) 来尝试梳理问题。

script1.bash

#!/bin/bash
log_name="${USER}_`date +"%Y%m%d-%H%M%S"`_${HOST}_.log"
log="/tmp/${log_name}"
log_tmp="/tmp/temp_logs"

err_count=0

finish()
{
   local ecode=0
   if [ $# -eq 1 ]; then
      ecode=
   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% 的时间该行未写入日志文件。然后我开始尝试几种不同的方法来处理这行输出。

  1. 回显并等待
echo "Error Count: ${err_count}" >> "${log}"
wait
  1. 备用打印方法
printf "Error Count: %d\n" ${err_count} >> "${log}"
  1. 无显式文件重定向
echo "Error Count: ${err_count}"
  1. 回声和睡眠
echo "Error Count: ${err_count}" >> "${log}"
sleep 0.2

其中,#1 和#2 各有 1% 的失败率,而 #4 有惊人的 99% 失败率。 #3 是唯一失败率为 0% 的方法。

在这一点上,我不知道为什么会发生这种行为,所以我向这里的专家请教任何见解。

(请注意,简单的解决方案是实施#3,但我想知道为什么会发生这种情况。)

未经测试,这看起来像是您的脚本与 tee 之间的竞争条件。通常最好避免多个程序同时写入同一个文件。

如果您坚持要有多个写入器,请确保它们都处于追加模式,在本例中使用 tee -a。附加到本地文件系统是原子的,因此所有写入都应该成功(对于网络文件系统而言不一定如此)。