現在、シェルスクリプトが同時ログに毎回失敗する理由を理解しようとしています。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}'
問題は、私は複数のサブを持っていること、ですプロセスは、それぞれログだけでなく、トラップも送信します(その間にロギングも実行されます)。私は問題をデバッグし、関数が同時に3回入力されたときにこれが起こることを発見しました。最初にmain
プロセスに入り、次にchild
と入力します。 date
の部分がl_text
の後に実行されると、main
getはchild
によって引き起こされるtrap
によって中断され、この中でtrap
は何かをログに記録しようとします。 child
とtrap
はロギングをうまく終了しますが、トラップ後にmain
が再開され、hostname
部分(おそらく)が実行され、このエラーが発生して失敗します。
main
は、ログステートメントの$(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) ${l_text}
部分を生成していて、うまく再開できないため、眠らないようです。私はローカル変数とスレッドセーフ出力メソッドを使用しているので、これは正常に動作するはずです。
これは私がここまで実行している一般的な並行性の問題ですか?あるいは、これはbashスクリプトのトラップメカニズムに特有のものですか?私はC言語でのSIGNAL処理の商品について知っているので、SIGNALハンドラでは特定の操作しか許されていません。しかし、私はbashスクリプトでSIGNALを扱うときにも同じ予防措置が当てはまるかどうかは分かりません。私はこれに関する文書を見つけようとしましたが、見つけられた文書のどれも、スクリプトのSIGNAL処理に関する問題の兆候を示していませんでした。
EDIT:
ここが問題を複製するために使用することができますactuall単純なスクリプトです:
#!/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コマンドも含まれていますので、by-by-oneエラーもあると想定しています。実際のエラーは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
@kojiro:ヒントありがとうございました...空白は元のものではなく、私は誤ってコードを減らして良い例にしました。私はこれを編集します。 – LiKao
ここでは 'thread'という名前は誤解を招いています.bashはスレッドではなくサブプロセスを使用しています...' $ 'の代わりに '$!'を 'trap" kill $ ?; exit 0 "INT TERM'と'INT' /' TERM'/'ALRM'に' SIG'( 'SIGINT')がありません。 –