2012-04-17 130 views
4

我目前正试图找出为什么shell脚本在并发日志记录中每隔一段时间就会失败。并发登录bash脚本

我有类似下面的外壳功能:

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,然后输入childl_textdate部分执行后,main get被trap中断,这是由child造成的,并且在此trap尝试记录某些内容。 childtrap完成他们的记录很好,但然后main恢复陷阱后,并尝试执行hostname部分(推测),并失败,并出现此错误。

所以好像main不喜欢在产生日志语句的$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) ${l_text}部分时进入睡眠状态,并且无法很好地恢复。我假设这应该工作得很好,因为我只是使用本地变量和线程安全输出方法。

这是我遇到的一般性并发问题吗?或者这是非常具体的在bash脚本中的陷阱机制?我知道C中SIGNAL处理的商品,所以我知道SIGNAL处理程序只允许某些操作。但是我不知道在处理bash脚本中的SIGNAL时是否也适用相同的预防措施。我试图找到关于这方面的文档,但是我找不到任何可以找到脚本中SIGNAL处理问题的迹象。

编辑

下面是一个实际工作中简单的脚本,可以用来复制的问题:

#!/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 

每过一段时间,该脚本将得到因为语法错误的杀害第5行是echo $text >> /dev/null,但由于语法错误也提到了hostname命令,类似于我在上面发布的命令,我假设还有一个错误,并且实际错误在第4行,这是local text="$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) $1"

有谁知道如何处理上述脚本来纠正它?我alread试过串建设迁出到一些临时变量:

log() { 
    local thedate=$(date +'%Y-%m-%d %H:%M:%S') 
    local thehostname=$(hostname -s) 
    local text="${thedate} ${thehostname} $1" 
    echo $text >> /dev/null 
} 

这种方式出现的错误不那么频繁,但它仍然存在,所以这不是一个真正的解决。

+5

围绕这些'='的空格是非法的。 – kojiro 2012-04-17 16:35:21

+0

@kojiro:谢谢你的提示......原文中不存在空格,我在将代码缩减为一个很好的例子时意外地介绍了它。我会编辑这个。 – LiKao 2012-04-17 16:54:03

+1

线程的名称在这里有误导,bash使用子进程,而不是线程...我想''!'而不是'$''在'trap'中kill $ ?; exit 0“INT TERM'和'INT' /'TERM' /'ALRM'缺少'SIG'('SIGINT')。 – 2012-05-04 07:15:56

回答

1

我会说这绝对是bash中的一个bug,我会鼓励你将它报告给bash开发者。至少,对于什么是语法正确的代码,您绝对不应该得到语法错误。

对于记录,我得到了与GNU bash, version 4.2.10(1)-release (x86_64-pc-linux-gnu)相同的结果。

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

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

更换

trap "log 'received ALRM'" ALRM 

使得脚本稳定我。

I know about the commodities of SIGNAL handling in C, so I am aware that only certain operations are allowed in SIGNAL handlers. However I am not aware if the same precautions also apply when handling SIGNALs in a bash script.

我想你不应该采取特别的预防措施,但显然在实践中,你这样做。鉴于问题在没有函数调用的情况下似乎消失了,我猜测bash中的某些内容不应该在它应该是或者不能再次进入的地方重新进入。

+0

好的,我已经报告过这个问题,但到目前为止我还没有收到任何有意义的反馈。我想他们已经在上面了,我希望他们能够在下一个版本中找到解决方案。 – LiKao 2012-05-14 13:18:20