2012-04-17 17 views
4

現在、シェルスクリプトが同時ログに毎回失敗する理由を理解しようとしています。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は何かをログに記録しようとします。 childtrapはロギングをうまく終了しますが、トラップ後に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 
} 

この方法はエラーはそれほど頻繁に表示されますが、それはまだ存在しているので、これが本当の修正はありません。

+5

'='の周りの空白は不正です。 – kojiro

+0

@kojiro:ヒントありがとうございました...空白は元のものではなく、私は誤ってコードを減らして良い例にしました。私はこれを編集します。 – LiKao

+1

ここでは 'thread'という名前は誤解を招いています.bashはスレッドではなくサブプロセスを使用しています...' $ 'の代わりに '$!'を 'trap" kill $ ?; exit 0 "INT TERM'と'INT' /' TERM'/'ALRM'に' SIG'( 'SIGINT')がありません。 –

答えて

1

これは間違いなくbashのバグであり、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

私は既に問題を報告しましたが、これまでのところ私は意味のあるフィードバックを受けていません。私は彼らがそれに乗っていると思うので、次のリリースの1つで解決策を見つけることを願っています。 – LiKao

関連する問題