私は現在、シェルスクリプトが時々同時ロギングで失敗する理由を理解しようとしています。
次のようなシェル関数があります。
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}'
問題は、複数のサブプロセスがあり、それぞれがログを記録したり、トラップを送信したりすることです (その間、ログも実行されます)。問題をデバッグしたところ、関数が同時に 3 回入力されたときにこれが発生することがわかりました。最初にmain
プロセスに入り、次にchild
. のdate
部分l_text
が実行された後、main
get は a によって中断され、これ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
目の構文エラーが原因で、このスクリプトが強制終了されることがあります。 1 つずつエラーもあり、実際のエラーは 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
}
この方法では、エラーの発生頻度は低くなりますが、それでも存在するため、これは実際の修正ではありません。