并发登录bash脚本

时间:2012-04-17 16:04:02

标签: bash concurrency signals bash-trap

我目前正试图弄清楚为什么shell脚本偶尔会在并发日志记录中失败。

我有一个像以下一样的shell函数:

log()
{
   local l_text=$1
   local l_file="/path/to/logs/$(date +%Y%m%d)_script.log"

   local l_line="$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) ${l_text}"

   echo ${l_line} >> ${l_file}
}

现在每隔一段时间就会因语法错误而失败:

/path/to/script.sh: command substitution: line 163: syntax error near unexpected token `)'
/path/to/script.sh: command substitution: line 163: `hostname -s) ${l_text}'

问题是,我有多个子流程,每个子流程都需要记录以及发送陷阱(在此期间也会执行记录)。我调试了这个问题并发现,当这个函数同时输入三次时会发生这种情况。首先进入main进程,然后进入child。在执行date l_text部分后,maintrap打断,该childtrap导致child尝试记录一下。 trapmain很好地完成了日志记录,但是在陷阱之后恢复hostname并尝试执行main部分(假定为)并因此错误而失败。

因此,似乎$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) ${l_text}不喜欢在生成日志语句的#!/bin/bash log() { local text="$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) $1" echo $text >> /dev/null } sub_process() { while true; do log "Thread is running" kill -ALRM $$ sleep 1 done } trap "log 'received ALRM'" ALRM sub_process & sub_process_pid=$! trap "kill ${sub_process_pid}; exit 0" INT TERM while true; do log "Main is running" sleep 1 done 部分时处于睡眠状态,并且不能很好地恢复。我假设这应该工作正常,因为我只是使用局部变量和线程安全输出方法。

这是我遇到的一般并发问题吗?或者这是否特别针对bash脚本中的陷阱机制?我知道C中SIGNAL处理的商品,所以我知道SIGNAL处理程序中只允许某些操作。但是,我不知道在bash脚本中处理SIGNAL时是否也适用相同的预防措施。我试图找到关于此的文档,但是我找不到的任何文档都没有给出脚本中SIGNAL处理问题的任何迹象。

修改

这是一个可用于复制问题的精简脚本:

echo $text >> /dev/null

由于第5行中的语法错误,此脚本每隔一段时间就会被杀死。第5行是local text="$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) $1",但由于语法错误也提到了hostname命令,类似于我上面发布的那个,我假设还有一个一个错误,实际错误在第4行,即log() { local thedate=$(date +'%Y-%m-%d %H:%M:%S') local thehostname=$(hostname -s) local text="${thedate} ${thehostname} $1" echo $text >> /dev/null }

有人知道如何处理上述脚本来纠正它吗?我已经尝试将字符串的构造移到一些临时变量中:

{{1}}

这样一来,错误的出现频率就会降低,但仍然存在,所以这不是一个真正的修复方法。

1 个答案:

答案 0 :(得分:1)

我会说这绝对是bash中的一个错误,我鼓励你向bash开发者报告。至少,你应该永远不会得到语法错误的语法错误代码。

为了记录,我使用GNU bash, version 4.2.10(1)-release (x86_64-pc-linux-gnu)获得与您相同的结果。

我发现您可以通过不在陷阱处理程序中调用函数来解决问题。例如。取代

trap "log 'received ALRM'" ALRM 

trap "echo $(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) received ALRM" ALRM

使我的脚本稳定。

  

我知道C中SIGNAL处理的商品,所以我知道   SIGNAL处理程序中只允许某些操作。但是,我   我不知道在处理SIGNAL时是否也适用相同的预防措施   在bash脚本中。

我想你不应该采取特别的预防措施,但显然你在实践中。鉴于问题似乎在没有函数调用的情况下消失了,我猜测bash中的某些东西或者不是重入的,它应该是或者在第一时间阻止重新进入。