我目前正试图弄清楚为什么 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
,main
get 被 a 中断,trap
这是由child
and in this引起的,它trap
试图记录一些东西。Thechild
和 thetrap
很好地完成了他们的日志记录,但随后main
在陷阱之后恢复并尝试执行该hostname
部分(假定)并失败并出现此错误。
因此,它似乎main
不喜欢在生成$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) ${l_text}
部分日志语句时进入睡眠状态并且不能很好地恢复。我假设这应该可以正常工作,因为我只是使用局部变量和线程安全的输出方法。
这是我在这里遇到的一般并发问题吗?还是这对于 bash 脚本中的陷阱机制非常具体?我知道 C 中 SIGNAL 处理的商品,所以我知道在 SIGNAL 处理程序中只允许某些操作。但是,我不知道在 bash 脚本中处理信号时是否也适用相同的预防措施。我试图找到这方面的文档,但我能找到的所有文档都没有表明脚本中的信号处理存在任何问题。
编辑:
这是一个可用于复制问题的实际简单脚本:
#!/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 行的语法错误而被杀死。第 5 行是echo $text >> /dev/null
,但是由于语法错误还提到了 hostname 命令,类似于我上面发布的那个,我假设有一个 -也有一个错误,实际错误在第 4 行,即local text="$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) $1"
.
有人知道如何处理上面的脚本来纠正它吗?我已经尝试将字符串的构造移到一些临时变量中:
log() {
local thedate=$(date +'%Y-%m-%d %H:%M:%S')
local thehostname=$(hostname -s)
local text="${thedate} ${thehostname} $1"
echo $text >> /dev/null
}
这样,错误出现的频率就会降低,但它仍然存在,因此这不是真正的修复。