4

私は現在、シェルスクリプトが時々同時ロギングで失敗する理由を理解しようとしています。

次のようなシェル関数があります。

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が実行された後、mainget は a によって中断され、これtrapは何かをログに記録しようとします。と はログを正常に終了しますが、トラップの後に再開され、(おそらく) その部分を実行しようとすると、このエラーで失敗します。childtrapchildtrapmainhostname

そのため、ログステートメント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
}

この方法では、エラーの発生頻度は低くなりますが、それでも存在するため、これは実際の修正ではありません。

4

1 に答える 1

1

これは間違いなく bash のバグであり、bash 開発者に報告することをお勧めします。少なくとも、構文的に正しいコードに対して構文エラーが発生することは決してありません。

記録のために、私はあなたと同じ結果を得るGNU bash, version 4.2.10(1)-release (x86_64-pc-linux-gnu).

トラップ ハンドラで関数を呼び出さないことで、問題を回避できることがわかりました。例:交換

trap "log 'received ALRM'" ALRM 

trap "echo $(date +'%Y-%m-%d %H:%M:%S') $(hostname -s) received ALRM" ALRM

スクリプトを安定させます。

私は C での SIGNAL 処理の商品について知っているので、SIGNAL ハンドラーでは特定の操作しか許可されていないことを認識しています。ただし、bash スクリプトで SIGNAL を処理するときにも同じ予防措置が適用されるかどうかはわかりません。

特別な予防措置を講じる必要はないと思いますが、実際にはそうしているようです。関数呼び出しなしで問題が解決したように見えることを考えると、bash の何かが本来あるべき場所に再入可能ではないか、そもそも再入を妨げていると思います。

于 2012-05-14T13:15:57.853 に答える