我目前正试图找出为什么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
,然后输入child
。 l_text
的date
部分执行后,main
get被trap
中断,这是由child
造成的,并且在此trap
尝试记录某些内容。 child
和trap
完成他们的记录很好,但然后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
}
这种方式出现的错误不那么频繁,但它仍然存在,所以这不是一个真正的解决。
围绕这些'='的空格是非法的。 – kojiro 2012-04-17 16:35:21
@kojiro:谢谢你的提示......原文中不存在空格,我在将代码缩减为一个很好的例子时意外地介绍了它。我会编辑这个。 – LiKao 2012-04-17 16:54:03
线程的名称在这里有误导,bash使用子进程,而不是线程...我想''!'而不是'$''在'trap'中kill $ ?; exit 0“INT TERM'和'INT' /'TERM' /'ALRM'缺少'SIG'('SIGINT')。 – 2012-05-04 07:15:56