11
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

シェルスクリプトでコマンド多重コントロール

Last updated at Posted at 2014-05-23

概要

一つ一つで見るとCPU負荷がそれほどじゃないコマンドを一気にバルク実行(並列実行)したいですよね?
大量のコマンドをリミット付けてバルク実行させますよね?
並列実行コントローラシェルスクリプトです。
投稿するには規模が大きいかな?とか思いましたがネットにサンプルないので必要かなと…
Cygwinでも動きます(たぶん)

コントローラソース

ディレクトリ配下のファイルをfindし実行用スクリプトに順次渡してバルク実行しています。
このソースは関数化してないので構造の解析把握が必要になります。
バルク実行は取り扱いがあれなので、内部動作は十分知っておいた方が良いと思います。

bulk_kicker.sh
# !/bin/bash

if [ $# -ne 1 ]; then
    echo "usage: " 1>&2
    echo "  ${0##*/} /path/name" 1>&2
  exit 1
fi

CheckDir=$1

ReturnNo=0
ExitCheckFileName="exists_loop_${0##*/}.flg"

# 並列同時実行数 初期値
# カレントディレクトリの config に多重数を書き込んで変更する
BulkLimit=6
BulkLimitControlFile="bulk_limit_${0##*/}.cfg"

# 終了判定用ファイル作成、存在しなくなれば終了
# ※ 緊急時にこのファイルを削除するとループ終了
echo 'if not exists this file, next step exit script.' > $ExitCheckFileName

echo "****  start  ****"

# ファイルリスト配列作成
# ※ ファイルリストをループする場合
echo "[$CheckDir]"
pushd $CheckDir >& /dev/null
unset ArrayFiles;
for LINE in `find ./ -name "*" | sort`; do
    if [ -s $LINE ]; then
        ArrayFiles+=($LINE)
    fi
done
unset LINE;
popd >& /dev/null

unset pids
for el in ${ArrayFiles[@]}; do
    if [ ! -e $ExitCheckFileName ]; then
        # 終了判定用ファイル、存在しなくなれば終了
        break;
    fi

    # 多重起動制御数取り込み
    if [ ! -e $BulkLimitControlFile ]; then
        echo $BulkLimit > $BulkLimitControlFile
    else
        BulkLimit=`head -n 1 $BulkLimitControlFile`
    fi

    while true
    do
        # 現多重数取得
        pnum=0
        unset switchPids
        for pid in ${pids[@]}; do
            GetStatus=`ps -p $pid | grep $pid`
            if [ "$GetStatus" != "" ]; then
                switchPids+=($pid)
                let pnum++
            fi
        done
        unset pids
        pids=(${switchPids[@]})
        if [ $pnum -lt $BulkLimit ]; then
            break;
        fi
        sleep 1
    done

    # 多重起動するshを & 付きで実行
    dno=`printf "%04d" ${#pids[*]}`
    echo "[`date '+%Y/%m/%d %T'`] "$dno 'sh ./bulker.sh' $CheckDir/$el
    eval 'sh ./bulker.sh' $CheckDir/$el &
    pids+=($!)
    # for pid in ${pids[@]}; do
    #     echo "pids $pid"
    # done
done

# 走っているプロセスの終了を待つ
while true
do
    # 現多重数取得
    unset switchPids
    for pid in ${pids[@]}; do
        GetStatus=`ps -p $pid | grep $pid`
            # GetId=`ps | grep $pid | awk '{print $1}'`
        if [ "$GetStatus" != "" ]; then
            switchPids+=($pid)
        fi
    done
    unset pids
    pids=(${switchPids[@]})
    if [ "${#pids[*]}" == "0" ]; then
        break;
    fi
    sleep 0.5
done

# dno=`printf "%04d" ${#pids[*]}`
# echo "pids $dno"

echo "****  end  ****"

exit $ReturnNo

呼ばれる側(参考)

bulker.sh
# !/bin/bash
# バルク実行テスト用なので適当にsleep入れてます
# 引数のファイルサイズをechoするだけのスクリプトです
path=$1
fsize=`wc -c $1 | awk '{print $1}'`
fsize=`printf "%10d" $fsize`
sleep 1
echo "[`date '+%Y/%m/%d %T'`] $fsize $path"
sleep 1

実行結果

相対パスを指定してますが、シェルを使う場合は絶対パスが良いです。

ekaneko@bibian ~/work/bulker % bash bulk_kicker.sh ../
****  start  ****
[../]
[2014/05/23 15:34:17] 0000 sh ./bulker.sh ..//./
wc: ..//./: ディレクトリです
[2014/05/23 15:34:17] 0001 sh ./bulker.sh ..//./arg_check.sh
[2014/05/23 15:34:17] 0002 sh ./bulker.sh ..//./bulker
wc: ..//./bulker: ディレクトリです
[2014/05/23 15:34:17] 0003 sh ./bulker.sh ..//./bulker/bulk_kicker.sh
[2014/05/23 15:34:17] 0004 sh ./bulker.sh ..//./bulker/bulk_limit_bulk_kicker.sh.cfg
[2014/05/23 15:34:17] 0005 sh ./bulker.sh ..//./bulker/bulker.sh
[2014/05/23 15:34:18]          0 ..//./
[2014/05/23 15:34:18]         87 ..//./arg_check.sh
[2014/05/23 15:34:18]          0 ..//./bulker
[2014/05/23 15:34:18]       2561 ..//./bulker/bulk_kicker.sh
[2014/05/23 15:34:18]          2 ..//./bulker/bulk_limit_bulk_kicker.sh.cfg
[2014/05/23 15:34:18]        145 ..//./bulker/bulker.sh
[2014/05/23 15:34:20] 0000 sh ./bulker.sh ..//./bulker/exists_loop_bulk_kicker.sh.flg
[2014/05/23 15:34:20] 0001 sh ./bulker.sh ..//./mysql
wc: ..//./mysql: ディレクトリです
[2014/05/23 15:34:20] 0002 sh ./bulker.sh ..//./mysql/mymysql.sh
[2014/05/23 15:34:20] 0003 sh ./bulker.sh ..//./mysql/mymysql_test.sh
[2014/05/23 15:34:21]         48 ..//./bulker/exists_loop_bulk_kicker.sh.flg
[2014/05/23 15:34:21]          0 ..//./mysql
[2014/05/23 15:34:21]       1681 ..//./mysql/mymysql.sh
[2014/05/23 15:34:21]        379 ..//./mysql/mymysql_test.sh
****  end  ****
ekaneko@bibian ~/work/bulker % 

解説

簡単に…
実行時に2つファイルを生成します(存在しない場合)

  1. bulk_limit_bulk_kicker.sh.cfg

  2. exists_loop_bulk_kicker.sh.flg

  3. limitはバルク数(同時実行数)です。実行中に変更も効きますけどタイミング悪いと飛びます。
    こんな感じに使います

% echo 3 > bulk_limit_bulk_kicker.sh.cfg
  1. exists_loop は緊急終了トリガーファイルです。消すとループを抜けるので移行の処理を行いません。
    こんな感じに使います。
% rm exists_loop_bulk_kicker.sh.flg
11
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?