バッチ処理の二重起動チェックをシェルだけで実現する方法

Linux

Linux系のОSでバッチを起動する場合は、シェルを作成して、そのシェルからJavaなどのプログラムを呼び出すケースがほとんどかと思います。


バッチで問題になるのが「バッチの重複起動」になります。
“バッチ突き抜け”とも言いますが、1つのバッチが終了する前に同じバッチが起動してしまうと、思わぬ不具合が発生してしまいます。
この場合、プログラムで重複起動をおこなわないような制御をおこなう必要があります。


今回は、このバッチ重複起動チェックをシェルだけで実現する方法を紹介します。


環境情報


  • OS:CentOS 7.6

pgrepコマンドとは


重複起動チェックで使用するコマンドは「pgrep」コマンドです。
「pgrep」コマンドは、プロセスが保持しているプロセス名属性からプロセスIDを取得するコマンド
になります。


「ps」コマンドと「grep」を足したコマンドですね。
psコマンドの出力結果をパイプ(|)で繋いでgrepで抽出することが多いかと思いますが、この操作を同時に実行することが「pgrep」コマンドになります。


基本的な文法は以下になります。

pgrep [オプション] [プロセスの特定パターン]

二重起動チェックのシェルプログラム


二重起動チェックのシェルプログラムは以下になります。
「pgrep」コマンドで自身のプロセス名でプロセス番号を取得し、そのプロセス番号と自身のプロセス番号と比較しています。
プロセス番号の比較結果が異なる場合は、自身のプロセスと同名の他プロセスが動作していると判断する、ということですね。


#!/bin/sh

echo "start"
PGREP=`pgrep -f $0 -o`
PGREP_RSLT=$?

if [ $$ != $PGREP  ];
then
  echo "$0は起動中です。二重起動チェックです。"
  exit 1
fi

sleep 180
echo "end"

上記サンプルプログラムを同時に実行すると、一方のシェルはチェックに掛かって起動できません。
二重起動チェックにかかりやすいように、180秒のスリープをおこないバッチ実行中の時間を長くとっています。


pgrepコマンドのオプションと特定パターン


二重起動チェックで使用している「pgrep」コマンドのオプションや、使用している特殊変数について説明していきます。


まずは「pgrep」コマンドのオプションです。
二重起動チェックで使用しているのは「-f」オプションと「-o」オプションになります。


「-f」「-o」オプション含めて、よく使用するオプションを紹介しておきます。


オプション フルオプション 説明

-f

–full

コマンドライン全体をパターンマッチの対象とする。

-o

–oldest

対象のプロセスから最も昔に起動されたものだけを対象とする。

-n

–newest

対象のプロセスから最も最近に起動されたものだけを対象とする。

-U ユーザ

–uid ユーザ

指定したユーザのプロセスを対象とする。「,」区切りで複数指定可能。

-v

–inverse

検索パターンの否定。


次に特殊変数についてです。


  • $0:実行中プロセスのシェルファイル名。
  • $?:直前に実行したコマンドの実行結果。成功時は「0」。失敗時は「0」以外。
  • $$:実行中プロセスのプロセスID。

この特殊変数は非常に便利です。
実際の動きを紹介していきます。


$0特殊変数。実行中プロセスのファイル名。


実行中プロセスのシェルファイル名は「test.sh」となります。
そのファイル名がそのまま特殊変数として格納されています。


#!/bin/sh

echo "start"
echo $0
echo "end"

test.sh

$?特殊変数。コマンド実行結果。


コマンドの実行結果が格納されています。
厳密にはコマンドの実行結果も参照、二重起動チェックに成功したか?失敗したか?についても処理分岐が必要となります。


#!/bin/sh

echo "start"
PGREP=`pgrep -f $0 -o`
echo $?
echo "end"

0

$$特殊変数。実行中プロセスのプロセスID。


実行中プロセスのプロセスIDが格納されています。


#!/bin/sh

echo "start"
echo $$
echo "end"

4269


シェルで外部ファイルを読み込む。サンプルシェルで解説。

Linux

今回は、シェルで外部ファイルを読み込む方法を紹介します。


シェルファイルは、非常に強力なスクリプトです。
使い方によっては、ちょっとした機能は実現することができます。


外部ファイルの読み込みパターン


外部ファイルを読み込むパターンとして、以下の2パターンについて説明します。


  • 外出し定義ファイルの読み込み
  • シェルからシェルを呼び出す

外出し定義ファイルの読み込み


シェルでちょっとした機能を実現する際に、さまざまなパラメータを外部ファイルに定義することが必要になる場合があります。
ファイル読み込み・書き込み系のシェルであればファイルパスを外部ファイルに定義したり、ですね。

そういった外部ファイル定義についてもシェルで可能です。


外部ファイル読み込みのサンプルシェル


サンプルシェルは以下になります。

#!/bin/sh
# 
# 外部ファイルの読み込み
# 

    echo "start."
    while read line
    do
        KEY=`eval echo $line | awk '{print $1}'`
        VAL=`eval echo $line | awk '{print $2}'`
        echo $KEY
        echo $VAL
    done < setting.config
    echo "end."

外部ファイルとなる「setting.config」は以下です。

line1    value1
line2    value2
line3    value3

実行結果は以下になります。

$ sh configLoad.sh
start.
line1
value1
line2
value2
line3
value3
end.

行データを繰り返し読み込む


行データを読み込む方法は以下になります。


while文で、自動的に最終行まで外部ファイルの読み込みをおこなっていきます。
読み込み対象ファイルをdone部分に記載することで、対象ファイルの読み込むをおこないます。


上記サンプルプログラムは、シェルファイルと同フォルダに、外部ファイルとなる「setting.config」が存在する状態のシェルファイルとなります。

    while read line
    do
        ・・・制御・・・
    done < 設定ファイルパス

lineに1行データが格納されるので、制御の部分にlineに対する処理を記載することになります。


awk(オーク)コマンドで列ごとに読み込み


awk(オーク)コマンドは、文字列を抽出するコマンドになります。
{print $N}で、N番目の列を抽出することができます。


上記のサンプルプログラムは、2列の行データなので、{print $2}までしかないですが、列をもっと増やしていきたい場合は、{print $3}といった具合に列の数を増やしていけば、対象の列データを読み込むことができます。


シェルからシェルを呼び出す


共通機能を定義したシェルを準備した場合、そのシェルを他のシェルから呼び出したい場合があります。

つまり、シェルからシェルを呼び出す、ということですね。


シェルからシェルを呼び出すサンプル


サンプルシェルは以下になります。

呼び出すシェルと呼び出されるシェルの2つになります。


呼び出す側のシェル

#!/bin/bash

`./sub.sh`
RET=$?
echo $RET

呼び出される側のシェル

#!/bin/sh
exit 10

シェルを呼び出す


シェルを呼び出す場合の記載は簡単です。

シェルのパスを「`」で囲めば呼び出すことができます。


`./sub.sh`

シェルから返り値を受け取る


シェルから返り値を受け取る場合は、呼び出される側は「$?」で取得できます。


RET=$?

呼び出される側は、「exit」を用いて返り値を返却できます。


exit 10



MySQLデータのインポートとエクスポート!圧縮と解凍する方法を紹介

Linux

こんにちは。
さくさくTECHブロガーのさくです。


今回は、Linux + MySQL の環境において、シェルを使ってエクスポートとインポートをおこなう方法を紹介します。


どういった場面を想定しているかといいますと、一番は定期実行のバッチですね。
例えば、1日1回、特定テーブルのデータをエクスポートする、といった要件があった場合。


その場合、エクスポートするコマンドをシェル化してクーロンに設定すると思います。
そういった時に使える手法です。


インポートについては、例えば実データが壊れてしまった場合の復旧ですね。
エクスポートしたデータをインポートすれば、データは元通りになります。


環境情報


OS:Linux
DB:MySQL


MySQLには「saku」というDBを準備します。
そのDBには「person」というテーブルが存在します。
テーブル構成は以下。


mysql> desc person;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| personID | int(11)      | NO   | PRI | NULL    | auto_increment |
| name     | varchar(32)  | NO   | MUL | NULL    |                |
| kana     | varchar(128) | NO   |     | NULL    |                |
| address  | varchar(512) | YES  |     | NULL    |                |
| gender   | char(1)      | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

また、あらかじめデータも格納しておきます。

mysql> select * from person;
+----------+--------+--------------+-----------+--------+
| personID | name   | kana         | address   | gender |
+----------+--------+--------------+-----------+--------+
|        4 | 山田   | ヤマダ       | 東京      | 0      |
|        5 | 高橋   | タカハシ     | 神奈川    | 0      |
|        6 | 田中   | タナカ       | 千葉      | 1      |
+----------+--------+--------------+-----------+--------+
3 rows in set (0.00 sec)

このテーブルに対して、エクスポート、および、インポートをおこないます。


エクスポート

まずはエクスポート。
エクスポートする条件も指定します。
「gender」が「1」のレコードのみをエクスポートします。
シェルは以下になります。

#!/bin/sh
# 
# エクスポートシェル
# 
mysqldump -h localhost \--single-transaction --skip-opt --extended-insert --quick --set-charset --no-create-info --no-autocommit \
  -u ※ユーザ名 -p※パスワード -h ※ホスト名 ※DB名 person \
  --where="gender = '0'" \
  | gzip > person.sql.gz 2>&1 | tee -a export.log

使用するコマンドは mysqldump コマンドです。
mysqldump コマンドで、「gender」が「1」のレコードのみをエクスポートします。
かつ、エクスポートするファイルはperson.sql.gzという圧縮ファイルとして出力し、エクスポート時のログをexport.logに出力します。


エクスポート結果を圧縮することで、仮に大量データをエクスポートすることになったとしても、ある程度はディスク使用率おさえることができます。


様々なオプションを指定していますが、各オプションの用途は以下になります。


オプション

説明

–single-transaction

これを設定しておくと、InnoDBについてエクスポートする際、他SQLがロックされないです。運用中システムについてエクスポートする際は、このオプションを指定した方が無難。

–skip-opt

「–opt」の設定をオフにします。

「–opt」の設定の中に「–add-locks」がありますが、これが有効だとエクスポート中にテーブルがロックされてしまう可能性があります。

それを防ぐために、–skip-optを設定して、「–opt」の設定をオフにします。

–extended-insert

出力されるダンプファイルについて、バルクインサートの形でSQLを作成します。

–quick

MySQLのマニュアルをみる限りでは、大量データをエクスポートする際はつけた方がいいみたいです。意味を理解しきれませんでしたが、たぶん、メモリ上にエクスポートデータを展開するタイミングの話のようです。このオプションを指定した方が、より高速なやり方を実施するようです。

–set-charset

出力するエクスポートするファイルに SET NAMES default_character_set を出力します。

–no-create-info

エクスポートするファイルに CREATE文を出力しません。

–no-autocommit

エクスポートするファイルに AutoCommitをオフにします。

具体的には、エクスポートするファイルのSQL先頭に「set autocommit=0;」を出力します。

かつ、最後に「commit;」を出力します。


エクスポートはこんな感じです。
エクスポートが完了するとperson.sql.gzというファイルが作成されます。


インポート


次にインポート。
インポートは、エクスポートシェルで作成したperson.sql.gzを解凍して、解凍したファイルを参照してインポートします。


シェルは以下になります。

#!/bin/sh
# 
# インポートシェル
# 
gunzip -d person.sql.gz >> insert.sql
mysql -u ※ユーザ名 -h ※ホスト名 -D ※DB名 -p※パスワード < insert.sql 2>&1 \ | tee -a import.log

まずは guzip コマンドで解凍して、「insert.sql」を出力。
gunzipに-d オプションをつけているので、元ファイルの「person.sql.gz」を削除して「insert.sql」に解凍結果を出力。


インポート自体はmysqlコマンドで実行しています。
リダイレクト「<」を指定して、解凍したSQLファイルをそのままインポートします。


まとめ


いかがでしたでしょうか?


今回はたった3行しか入っていないテーブルに対してのエクスポートなので性能は意識する必要はないのですが、数億件のエクスポートする場合は性能が大事になります。
紹介したオプションを指定すれば、極力、サーバ性能に沿ったパフォーマンスを出せると思っています
参考にしてください。


それではまた!



さくさくのTips!よく使うLinuxコマンド集

Linux

こんにちは。
さくさくTECHブロガーの「さく」です。


Linuxコマンドで忘れやすいコマンドをまとめていきます。

自分用っていう部分もありますが、もしよければ参考にしてください。


Linuxコマンド

コピー

強制的にコピーするときは「-f」。

強制的というのは、いちいち”上書きします。よろしいですか?”をきかない、ということ。


cp -f a.txt b.txt


ディレクトリをコピーするときには「-r」。

コピー元ディレクトリ配下のファイル、および、サブフォルダ・サブファイルもコピーする。


cp -r directory1 directory1


ファイルの属性を保持したままコピーするときは「-p」。

ファイルの属性とは、ファイルのタイムスタンプ・権限、といったメタ情報。


cp -p a.txt b.txt

リスト

よく使うオプションは「-la」。

「l」は、詳細表示。

「a」は、全て表示。(先頭に . がついているファイルとか)


ls -la

ファイルのタイムスタンプをミリ秒まで表示したい場合は、「–full-time」


ls -la --full-time

履歴

コマンドの実行履歴をみたい場合はhistory

現在ログインしているユーザのコマンド実行履歴なので、ユーザを切り替えた場合は、切り替え前の実行履歴は表示されない。


history

履歴コマンドを実行すると、大概は大量にコマンドが出てくるので、パイプでつないでお目当てのコマンドを探す


history | grep ○△□

※「○△□」は探す対象のコマンドなど

エイリアス

OSに設定されてるエイリアスを確認する時はエイリアスコマンド


alias

登録されているエイリアスコマンドが確認できるが、たいがいのLinuxでは「ll(エルエル)」は “ls -l –color=auto” のエイリアス。


所有者とグループの変更

所有者・グループの変更はchownコマンド。


chown owner:group ○△□

「owner」はオーナー名。

「group」はグループ名。

「○△□」は、対象のフォルダ名とファイル名。


圧縮・解凍

一番簡単な圧縮コマンドは「gzip」


gzip file

解凍も「gzip」でいける
「-d」をつけると、圧縮ファイルは削除される。


gzip -d file

viエディタ

Linux上でファイルを直接修正する場合はviコマンド



vi ファイル名

「i」で編集モード、「esc」でコマンドモード、を切り替える。

コマンドモードでよく使うコマンドは以下。

コマンド 説明
/ (スラッシュ)

スラッシュをいれて検索ワードを入力。

エンターで検索開始。

n(小文字)で次検索。

N(大文字)で前検索。

Shift + g

ファイルの末尾に移動。

dd(dを2回押し)

1行削除

yy(yを2回押し)

行コピー

p

ペースト

シェル

シェルの実行

シェルを実行するときは、シェルが存在するディレクトリを明確にしたうえでシェルファイル名を指定するだけ。


./shell.sh


シェルをバックグラウンドで実行するときは、末尾に「&」をつける。

バックグラウンドで実行といっても、「huponexit」の設定次第では、実行端末を閉じるとシェル自体は停止するので注意が必要。


./shell.sh &