BASHループ、カウンタ、サブプロセスカウンタが機能しません。

BASHループ、カウンタ、サブプロセスカウンタが機能しません。
  • 質問:親スクリプトがランダムに多すぎるワーカースクリプトを生成します。
  • 疑う:bashのバグがありますが認識できません。
  • オペレーティングシステム:Ubuntu 16.04.03 LTS
  • GNU バッシュ:バージョン 4.3.48(1) - リリース済み(x86_64-pc-linux-gnu)
  • MySQL:5.7.21 (MySQLリポジトリ)

親スクリプトの役割は、MySQLからデータを取得し、MySQLのデータを使用してバックグラウンドでワーカースクリプトを実行することです。親スクリプトは、すべてのデータが処理されるまで7つ以下のワーカースクリプトを実行することを担当します。この方法は、約1ヶ月前まで何年も完璧に機能していました。私の問題は最近の更新によって引き起こされたと思われます。ロジックは次のとおりです。

  1. 親スクリプトはMySQLサーバーからデータを取得します。
  2. 親スクリプトはバックグラウンドで繰り返され、ワー​​カースクリプトを起動してMySQLから取得したデータを渡します。
  3. ジョブスクリプトは「ロックファイル」を生成して書き込みます。
  4. 親スクリプトは、生成されたワーカースクリプトの数とワーカーロックファイルの数を監視し、最大7つのワーカースクリプトを実行し続けます。

私は、子プロセスがロックファイルを設定して書き込む時間がある前に、親スクリプトが複数の子プロセスを繰り返し生成できることを知っています。これが私がこの状況を避けるために子生成数(SPWNCNT)を維持する理由です。私が言ったように、私は以前はうまくいきましたが、もう動作しません。

これはスクリプトの一部です。

#!/bin/bash

......


###########################
# Loop through all unique codes and process them.
echo "$0: NOTICE: Started processing codes; `date`."
COMCNT=0
SPWNCNT=0
TPCNT=0
while read COMNUM
do
  # Only permit a certain number of child processes
  # so to not overload the machine or chew up to
  # many MySQL connections.
  PCNT=`ls -1 $TEMPDIR/*.Worker.lock 2>/dev/null | wc -l`
  (( TPCNT = PCNT + SPWNCNT ))
  TPCNT=`echo ${TPCNT#-}`
  while [[ $TPCNT -gt 6 ]]
  do
    # Too many child processes.
    sleep 1
    PCNT=`ls -1 $TEMPDIR/*.Worker.lock 2>/dev/null | wc -l`
    (( TPCNT = PCNT + SPWNCNT ))
    TPCNT=`echo ${TPCNT#-}`

    if [[ $SPWNCNT -gt 0 ]]
    then
      (( SPWNCNT = SPWNCNT - PCNT ))
      if [[ $SPWNCNT -lt 0 ]]
      then
        SPWNCNT=0
      fi
    fi

  done # while -gt 6

  # Spawn a worker process
  ./Worker.sh $COMNUM &
  (( SPWNCNT = SPWNCNT + 1 ))
  (( COMCNT = COMCNT + 1 ))

  if [ "$VERBOSE" = "true" ]
  then
    echo "$0: NOTICE: Spawned $COMNUM, count $COMCNT ($SPWNCNT); `date`"
  fi

done << COMNUM_EOF
  `cat $GEN_RATES_COMNUM_FILE | $MyCMD -B -N $MyDB`
COMNUM_EOF

......

以下は問題のデバッグ出力です(#!/ bin / bash -xを使用)。

...... many lines showing same logic working correctly ......
++ wc -l
++ ls -1 '/tmp/*.Worker.lock'
+ PCNT=0
+ ((  TPCNT = 0 + 7  ))
++ echo 7
+ TPCNT=7
+ [[ 7 -gt 0 ]]
+ ((  SPWNCNT = 7 - 0  ))
+ [[ 7 -lt 0 ]]
+ [[ 7 -gt 6 ]]
+ sleep 1
++ wc -l
++ ls -1 /tmp/032500.Worker.lock /tmp/032800.Worker.lock 
/tmp/033300.Worker.lock /tmp/033900.Worker.lock /tmp/034700.Worker.lock 
/tmp/035400.Worker.lock /tmp/035600.Worker.lock /tmp/036000.Worker.lock 
/tmp/036200.Worker.lock /tmp/036400.Worker.lock /tmp/036600.Worker.lock 
/tmp/037000.Worker.lock /tmp/039100.Worker.lock /tmp/039600.Worker.lock 
/tmp/040200.Worker.lock /tmp/040400.Worker.lock /tmp/041000.Worker.lock 
/tmp/041200.Worker.lock /tmp/041600.Worker.lock /tmp/041800.Worker.lock 
/tmp/042000.Worker.lock /tmp/043600.Worker.lock /tmp/046200.Worker.lock 
/tmp/048600.Worker.lock /tmp/049600.Worker.lock /tmp/052000.Worker.lock 
/tmp/052300.Worker.lock /tmp/054300.Worker.lock /tmp/054500.Worker.lock 
/tmp/054900.Worker.lock /tmp/055300.Worker.lock /tmp/056000.Worker.lock 
/tmp/056200.Worker.lock
/tmp/056600.Worker.lock /tmp/056900.Worker.lock /tmp/057800.Worker.lock 
/tmp/058600.Worker.lock /tmp/060400.Worker.lock /tmp/060700.Worker.lock
+ PCNT=39
+ ((  TPCNT = 39 + 7  ))
++ echo 46
+ TPCNT=46
+ [[ 7 -gt 0 ]]
+ ((  SPWNCNT = 7 - 39  ))
+ [[ -32 -lt 0 ]]
+ SPWNCNT=0
+ [[ 46 -gt 6 ]]
+ sleep 1
++ wc -l
++ ls -1 /tmp/032500.Worker.lock /tmp/032800.Worker.lock 
/tmp/033300.Worker.lock /tmp/033900.Worker.lock /tmp/034700.Worker.lock 
/tmp/035400.Worker.lock /tmp/035600.Worker.lock /tmp/036000.Worker.lock 
/tmp/036200.Worker.lock /tmp/036400.Worker.lock /tmp/036600.Worker.lock 
/tmp/037000.Worker.lock /tmp/039100.Worker.lock /tmp/039600.Worker.lock 
/tmp/040200.Worker.lock /tmp/040400.Worker.lock /tmp/041000.Worker.lock 
/tmp/041200.Worker.lock /tmp/041600.Worker.lock /tmp/041800.Worker.lock 
/tmp/042000.Worker.lock /tmp/043600.Worker.lock /tmp/046200.Worker.lock 
/tmp/048600.Worker.lock /tmp/049600.Worker.lock /tmp/052000.Worker.lock 
/tmp/052300.Worker.lock /tmp/054300.Worker.lock /tmp/054500.Worker.lock 
/tmp/054900.Worker.lock /tmp/055300.Worker.lock /tmp/056000.Worker.lock 
/tmp/056200.Worker.lock
/tmp/056600.Worker.lock /tmp/056900.Worker.lock /tmp/057800.Worker.lock 
/tmp/058600.Worker.lock /tmp/060400.Worker.lock /tmp/060700.Worker.lock
+ PCNT=39
+ ((  TPCNT = 39 + 0  ))
++ echo 39
+ TPCNT=39
+ [[ 0 -gt 0 ]]
+ [[ 39 -gt 6 ]]
+ sleep 1

それでは、スクリプトはどのように7つの実行中のプロセス(TPCNT)(正しいターゲット)から39、46にジャンプしますか?ロジックがこれをどのように受け入れるかはわかりません。デバッグ出力は、bashシェルが落ちる以外にこれについての説明を提供しないようです。

答え1

後でこの投稿を探している人のために...これは私の解決策に基づいています。モジュラー答えは上記と同じです。モジュラー実際に賞賛される価値があります。

#!/bin/bash

.....

# Intialize the Child Process List (array)
CPLIST=()

# Max concurrent child processes
MAXCP=6

# Worker loop to spawn and monitor child (worker) processes
while [[ SOME-CONDITION ]]
do

  # Monitor Child Process List (array)
  # Ensure that we don't exceed Max Child Processes
  if [[ ${#CPLIST[@]} -gt $MAXCP ]]
  then
    while [[ ${#CPLIST[@]} -gt $MAXCP ]]
    do
      sleep 1
      # Check each child processes to see if it's still running.
      for idx in ${!CPLIST[@]}
      do
        # Is child process still alive?
        kill -0 ${CPLIST[$idx]} 2>/dev/null
        if [[ $? -gt 0 ]]
        then
          # Child process is no longer running.
          # Remove it from the child process list (array).
          unset CPLIST[$idx]
        fi # if $?
      done # for idx
    done # while MAXCP
  fi # if MAXCP

  # Spawn a child process
  ./MyProgram &
  # Append Child Process PID to Child Process List
  CPLIST=(${CPLIST[@]} $!)

done # while

.....

# (end of file)

関連情報