夜間バッチや月次処理など、業務で定期的にファイルを受け渡すシーンでは、単純なコピーや移動では不十分なことが多々あります。特に複数プロセス間でのファイル衝突や、処理タイミングのズレによる誤動作、転送失敗によるデータ欠損などは、現場でよくある問題です。今回ご紹介する「ファイル連携スクリプト」は、そうした問題を根本的に回避しつつ、安全に中間ファイルを受け渡すための実用的なシェルスクリプトです。
JP1などのジョブ管理ツールと組み合わせて動作させることも可能で、.finや.endといった制御ファイルによる状態監視、排他ロック、MD5整合性チェックなど、現場で「絶対にミスできない連携処理」を支えるための工夫が詰まっています。手動運用を減らし、自動化を進めたいと考えている方には、特に有用な構成です。
ファイル連携スクリプトの概要と役割
業務バッチ処理や夜間の定期ジョブ運用において、ファイルを安全かつ確実に受け渡す仕組みは欠かせません。特に、複数プロセスや他システムとの中間連携が発生する現場では、単純な mvや cpでは事故につながることもあります。
そこで登場するのが、状態監視や排他制御、ログ出力を標準で備えたファイル連携専用のスクリプトです。このスクリプトは、実運用の現場で実績のある堅牢な作りとなっており、市販ツールでも補いきれない「一時ファイルの取扱い」や「受信検知のタイミング制御」などの問題を解決します。
ファイル連携スクリプトの目的
ファイル連携スクリプトの主な目的は、業務間でのファイル授受を安全かつ自動的に行うことです。 特に以下のような目的で使用されます。
目的 | 詳細 |
---|---|
状態の明確化 | 完了ファイル(.fin/.end)による受信判定 |
排他制御 | 同一タイミングでの多重実行を防止 |
エラー制御 | 不整合ファイルや中断時のログ通知 |
再処理性の確保 | ログに基づく処理状態の追跡と再実行 |
ファイル管理の課題と解決アプローチ
現場では、単にファイルを送っても、受け取り側の準備が整っていない場合があります。また、複数のバッチ処理が並列で動いていると、同じファイルを同時に触ってしまうケースも少なくありません。これらの問題に対して、本スクリプトでは以下のアプローチを取っています。
- .finや.endなどの完了ファイルの存在をチェックして受信開始の合図とする
- 一時ファイルを使用して中途半端なファイル処理を防止する
- 排他ロック機構により二重実行をブロックする
- MD5チェックによる完全一致の検証を取り入れて信頼性を担保する
これらの処理により、ファイル管理にありがちな「処理中に上書きされる」「半分だけ転送されたファイルを誤処理する」といったリスクを大幅に軽減できます。
スクリプト設計の基本方針
本スクリプトは、以下の基本方針のもとに設計されています。
- シンプルな引数制御(送信・受信モード)
- 外部設定ファイル(logger.shrc, utils.shrc)による共通化
- 処理ログは常にログファイルへ出力
- 異常時は即座にエラーログを記録し、必要に応じて中断
- テストモードでの検証が可能な作り(本番前の試験に対応)
これにより、ファイル授受の信頼性を高めつつ、再利用性と保守性を確保しています。
今後の章では、設計構成や実際の運用例についても具体的に解説していきます。
設計書の構成と設計要素

このファイル連携スクリプトは、現場での運用実績に基づいて構築されており、堅牢性と拡張性を意識した構成となっています。JP1や定時バッチなど既存ツールとの併用を前提とした仕様となっており、再利用性を高めるために設計書レベルでの明確な構造化を意識しています。ここでは、スクリプト全体の設計前提と、使用している変数や関数群について具体的に紹介していきます。
スクリプト設計の前提条件
このスクリプトは、以下のような前提条件を元に設計されています。
項目 | 内容 |
---|---|
OS | RHEL系Linux(CentOS/AlmaLinux/Rocky Linux) |
実行ユーザー | 一般ユーザー(root権限は不要) |
依存スクリプト | logger.shrc, utils.shrc(共通モジュール) |
前提構成 | scripts/com 配下に共通クラス、scripts/bin 配下に本体を設置 |
ログ出力 | 共通ログクラスによるファイル出力 |
これらの前提により、共通関数との連携やエラー処理の標準化を可能にしています。
使用する引数と変数一覧
スクリプトは、実行モード(送信/受信)や対象ファイル種別を引数として受け取ります。加えて、内部では各種の制御変数が使用されています。
変数/引数 | 用途 |
---|---|
-m | mode(send または recv) |
-t | target(データ or 完了ファイル) |
src_dir | 送信元ディレクトリ |
dst_dir | 受信先ディレクトリ |
LOCK_FILE | 排他制御用のロックファイル |
DATE_STR | 実行タイムスタンプ |
実行例は以下のようになります。
sh fileTransfer.sh -m send -t data
引数が不正である場合は、usage関数によりヘルプ表示されます。
実装されている主要関数の詳細
このスクリプトは可読性と保守性を高めるため、関数単位で明確に処理を分離しています。代表的な関数は以下の通りです。
関数名 | 役割 |
---|---|
usage() | 引数エラー時の使い方表示 |
checkArgs() | モードとターゲットの妥当性確認 |
lockProcess() | 排他制御のためのロック取得 |
execSend() | ファイル送信処理の本体 |
execRecv() | ファイル受信処理の本体 |
getMd5sum() | ファイルの整合性チェック用MD5算出 |
それぞれの関数は共通ロガーを通じてログ出力を行い、エラー発生時には即時中断またはリトライ処理が可能な構成となっています。関数の役割が明確なため、導入後のカスタマイズや拡張も容易です。
ファイル連携スクリプトの設定手順
このセクションでは、実際にファイル連携スクリプトを稼働させるための各種設定手順について解説します。対象読者は、すでにLinux上で基本的なシェルスクリプトの実行経験があることを前提としています。
今回のスクリプトでは、共通関数やログ出力クラスを活用し、再利用性と保守性を高めた構成となっており、最小限の設定で即座に運用に組み込めるよう設計されています。
ここでは、想定する実行環境、必要な設定ファイル群、それらの読み込み方法やディレクトリ構成など、導入前に整えておくべき具体的な準備作業を一つずつ明示していきます。
前提となる実行環境
Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。
実行環境
BASE_DIR(任意のディレクトリ)
- scripts
- bin(実行スクリプト格納領域)
- <<各種実行スクリプト>>.sh (実行ファイル)
- com(共通スクリプト格納領域)
- logger.shrc(共通ログ出力ファイル)
- utils.shrc(共通関数定義ファイル)
- etc(設定ファイル等の格納領域)
- infraMessage.conf(メッセージ定義ファイル)
- log(スクリプト実行ログの格納領域)
- スクリプト名.log
- tmp(テンポラリ領域)
- rep(レポート出力領域)
- bin(実行スクリプト格納領域)
スクリプトを正しく動作させるためには、実行するサーバー環境やディレクトリ構成、権限などに一定の前提があります。以下に実行環境としての要件をまとめます。
項目 | 要件内容 |
---|---|
OS | RHEL系Linux(CentOS、Rocky、Almaなど) |
Bash | /bin/bash を使用 |
実行ユーザー | 一般ユーザー(sudo不要) |
ディレクトリ構成 | 以下に準拠:scripts/bin、com、log、tmp、rep、etc |
依存ファイル | logger.shrc、utils.shrc(scripts/com配下に配置) |
特に、scripts/com 配下にある共通クラスの存在は必須となります。環境変数やPATHに依存せず、ローカルで自己完結できる構造が前提です。
ファイル連携スクリプト
ファイル連携スクリプトは、受信・転送・退避・削除といった一連の処理を自動化し、安全かつ確実にファイルを中継するための仕組みです。中間ディレクトリや排他制御、ログ出力を組み合わせて、実運用での信頼性を高めています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
#!/bin/sh # fileTransfer.sh #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # 関数名 :fileTransfer.sh(スクリプト本体) # 概要 :ファイル送受信の状態管理付き転送処理 # 説明 : # 指定されたファイルを送信側・受信側で管理する仕組みを一体化し、 # .end/.fin ファイルによる状態遷移を制御しながらファイルの整合性を保証する。 # 処理モードは `-m send` または `-m recv` により切り替えられる。 # 送信時はMD5でハッシュ検証後に`.end`を出力、受信時は`.end`確認後に`.fin`を出力。 # ロック制御によって多重起動を防止し、安全な排他処理を実現する。 # また、不正なユーザーでの実行や引数不足、ファイル不整合時には即座にエラー終了する。 # # 引数 : # -m <mode> :"send" または "recv" を指定(処理モード) # -f <file_path> :処理対象のファイルパス # -t <target_dir> :出力先または受信先ディレクトリのパス # # 戻り値 : # 0(正常終了)、1(警告)、2(異常終了)※JOB_OK, JOB_WR, JOB_ERで制御 # # 使用箇所 : # - システム間の中間ファイル転送 # - バッチ処理での安全なファイル受け渡し # - 統合システムやETL的用途でのデータ連携ステップ # ------------------------------------------------------------------ #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # <変更履歴> # Ver. 変更管理No. 日付 更新者 変更内容 # 1.0 PR-0001 2025/07/30 Bepro 新規作成 #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # 共通クラスの読み込み . "$(dirname "$0")/../com/utils.shrc" . "$(dirname "$0")/../com/logger.shrc" setLANG utf-8 runAs root "$@" # ------------------------------------------------------------------ # variables (変数の宣言領域) # ------------------------------------------------------------------ scope="var" # ======================================== # 定数定義 # ======================================== readonly JOB_OK=0 readonly JOB_WR=1 readonly JOB_ER=2 # ---------------------------------------------------------- # functions (関数を記述する領域) # ---------------------------------------------------------- scope="func" # ------------------------------------------------------------------ # 関数名 :terminate # 概要 :終了時のロック解除処理 # 戻り値 :なし # 使用箇所 :trapによる終了時呼び出し # ------------------------------------------------------------------ terminate() { releaseLock } # ------------------------------------------------------------------ # 関数名 :getFileStatus # 概要 :ファイル転送状態を判定(INITIAL/LOADING/LOADED/COMPLETED) # 引数 :$1 = 対象ファイルのパス # 戻り値 :状態文字列(INITIAL等) # 使用箇所 :送信・受信処理判定時 # ------------------------------------------------------------------ getFileStatus() { status="UNEXPECTED" [ ! -f "$1" ] && [ ! -f "$1.end" ] && [ ! -f "$1.fin" ] && status="INITIAL" [ -f "$1" ] && [ ! -f "$1.end" ] && [ ! -f "$1.fin" ] && status="LOADING" [ -f "$1" ] && [ -f "$1.end" ] && [ ! -f "$1.fin" ] && status="LOADED" [ -f "$1" ] && [ -f "$1.end" ] && [ -f "$1.fin" ] && status="COMPLETED" echo "$status" } # ------------------------------------------------------------------ # 関数名 :checkArgs # 概要 :引数の妥当性確認(ファイル・ディレクトリ存在) # 引数 :$1 = 入力ファイルパス、$2 = 出力ディレクトリパス # 戻り値 :なし(異常時はexit) # 使用箇所 :main処理前 # ------------------------------------------------------------------ checkArgs() { if [ $# -lt 2 ]; then logOut "ERROR" "Insufficient number of arguments." exit ${JOB_ER} fi if echo "$1" | grep -q '[*?]'; then logOut "ERROR" "Wildcard characters are not allowed in file path: [$1]" exit ${JOB_ER} fi if [ ! -f "$1" ]; then logOut "ERROR" "Specified file does not exist: [$1]" exit ${JOB_ER} fi if [ ! -d "$2" ]; then logOut "ERROR" "Specified directory does not exist: [$2]" exit ${JOB_ER} fi } # ------------------------------------------------------------------ # 関数名 :usage # 概要 :使用方法を表示して終了 # 引数 :なし # 戻り値 :なし(常にexit) # 使用箇所 :引数ミス時 # ------------------------------------------------------------------ usage() { echo "Usage: $0 -m <send|recv> -f <file_path> -t <target_dir>" echo " -m mode (send = send file, recv = receive file)" echo " -f file path (path to the source file)" echo " -t target dir (path to the destination directory)" exit ${JOB_ER} } # ------------------------------------------------------------------ # 引数解析(getopts) # ------------------------------------------------------------------ mode="" src_fp="" dst_dir="" while getopts "m:f:t:" opt; do case "$opt" in m) mode="$OPTARG" ;; f) src_fp="$OPTARG" ;; t) dst_dir="$OPTARG" ;; *) usage ;; esac done # 引数が一つもなければ usage 表示 if [ "$OPTIND" -eq 1 ]; then logOut "ERROR" "No arguments provided." usage fi if [ -z "$mode" ] || [ -z "$src_fp" ] || [ -z "$dst_dir" ]; then logOut "ERROR" "Missing required arguments." usage fi # モード値の妥当性チェック if [ "$mode" != "send" ] && [ "$mode" != "recv" ]; then logOut "ERROR" "Invalid mode specified: [$mode]" usage fi # ------------------------------------------------------------------ # pre-process (事前処理ロジックを記述する領域) # ------------------------------------------------------------------ scope="pre" startLog trap "terminate" 0 1 2 3 15 if ! acquireLock; then logOut "ERROR" "排他ロックを取得できませんでした。" exit ${JOB_ER} fi checkArgs "$src_fp" "$dst_dir" dst_fp="${dst_dir}/${src_fp##*/}" # ------------------------------------------------------------------ # main-process (メインロジックを記述する領域) # ------------------------------------------------------------------ scope="main" if [ "$mode" = "send" ]; then # ========================= # モード: 送信(sender側) # ========================= file_stat=$(getFileStatus "$dst_fp") logOut "INFO" "送信先ファイル [$dst_fp] の状態: [$file_stat]" if [ "$file_stat" = "UNEXPECTED" ]; then logOut "ERROR" "不正な状態のファイルが存在します。: [$dst_fp]" exit ${JOB_ER} fi if [ "$file_stat" = "COMPLETED" ]; then for f in "$dst_fp" "$dst_fp.end" "$dst_fp.fin"; do logOut "INFO" "既存ファイルを削除します: $f" rm -f "$f" || { logOut "ERROR" "ファイル削除に失敗しました: $f" exit ${JOB_ER} } done file_stat="INITIAL" fi if [ "$file_stat" = "LOADED" ]; then logOut "INFO" "受信側が未完了のため、送信スキップ: [$dst_fp.end]" exit ${JOB_OK} fi if [ "$file_stat" = "INITIAL" ] || [ "$file_stat" = "LOADING" ]; then cp -pf "$src_fp" "$dst_fp" if [ $? -ne 0 ]; then logOut "ERROR" "ファイルのコピーに失敗しました。" exit ${JOB_ER} fi src_hash=$(getMd5sum "$src_fp") dst_hash=$(getMd5sum "$dst_fp") if [ "$src_hash" != "$dst_hash" ]; then logOut "ERROR" "MD5値が一致しません。転送失敗 [$src_hash] != [$dst_hash]" exit ${JOB_ER} fi echo "$src_hash" > "${dst_fp}.end" logOut "INFO" "送信完了。MD5一致: [$src_hash]" fi elif [ "$mode" = "recv" ]; then # ========================= # モード: 受信(receiver側) # ========================= file_stat=$(getFileStatus "$src_fp") logOut "INFO" "受信元ファイル [$src_fp] の状態: [$file_stat]" if [ "$file_stat" = "UNEXPECTED" ]; then logOut "ERROR" "不正な状態のファイルが存在します。: [$src_fp]" exit ${JOB_ER} fi if [ "$file_stat" = "COMPLETED" ]; then logOut "INFO" "受信済みです。 [$src_fp.fin]" exit ${JOB_OK} fi if [ "$file_stat" = "INITIAL" ] || [ "$file_stat" = "LOADING" ]; then logOut "INFO" "送信処理が未完了のため、受信スキップします。" exit ${JOB_OK} fi if [ "$file_stat" = "LOADED" ]; then cp -pf "$src_fp" "$dst_fp" if [ $? -ne 0 ]; then logOut "ERROR" "ファイルの受信に失敗しました。" exit ${JOB_ER} fi org_hash=$(cat "${src_fp}.end") new_hash=$(getMd5sum "$dst_fp") if [ "$org_hash" != "$new_hash" ]; then logOut "ERROR" "MD5検証失敗。 [$org_hash] != [$new_hash]" exit ${JOB_ER} fi touch "${src_fp}.fin" logOut "INFO" "受信完了。MD5一致: [$new_hash]" fi fi # ---------------------------------------------------------- # post-process (事後処理ロジックを記述する領域) # ---------------------------------------------------------- scope="post" logOut "INFO" "fileTransfer.sh を正常終了します。" exitLog ${JOB_OK} |
各種設定ファイルと読み込み方法
スクリプト本体では、可読性と再利用性を担保するために設定情報を外部ファイルから読み込む設計を採用しています。特に以下の2つが中心となります。
設定ファイル | 内容 |
---|---|
logger.shrc | ログ出力関数の定義。全てのログ操作をここに集約 |
utils.shrc | 共通関数の定義(引数検査、文字列処理など) |
読み込み方法としては、スクリプト冒頭にて以下のように記述します。
. $(dirname "$0")/../com/logger.shrc
. $(dirname "$0")/../com/utils.shrc
これにより、ファイルパスが変動しても、相対パスで確実に共通処理を取り込むことができます。また、logger.shrcはスクリプト中のすべてのログ出力に対応しているため、標準出力やエラーログの混在を避けることが可能になります。
ログ出力・中間ディレクトリの設定
ファイル連携の運用において、ログ管理と一時ファイルのディレクトリ設計は非常に重要です。ログが追えない、あるいは競合によって中間ファイルが壊れるといった事象を避けるため、下記のようにディレクトリを明確に分離してください。
用途 | 推奨ディレクトリ |
---|---|
ログファイル出力 | scripts/log |
一時ファイル作成 | scripts/tmp |
バックアップ退避 | scripts/rep |
各種設定ファイル | scripts/etc |
ログ出力はすべて以下の形式で共通化します。
logOut "INFO" "転送完了:${target_file}"
logOut "ERROR" "送信失敗:${target_file}"
中間ファイルや作業ファイルについては、scripts/tmp に限定することで、他プロセスとの競合や削除忘れによる問題を未然に防止します。また、scripts/rep 以下にバックアップとして一定期間ファイルを退避させる構造を取ることで、リカバリや検証用途にも対応可能です。
これらの設計要素を取り入れることで、運用上のトラブルを大幅に軽減し、保守性の高いファイル連携環境を構築することができます。特にログ出力や中間処理の一貫性を保つことは、後工程のバッチ連携やエラー対応の効率に直結するため、初期構築段階で丁寧に整備しておくことを推奨します。
ファイル転送スクリプトの基本構造と使い方

ファイル転送はシステム間のデータ連携において頻繁に利用される重要な処理です。単純なコピー処理と異なり、ログの記録、排他制御、中間ディレクトリの利用、障害時の再送設計など、業務運用に耐える構成が求められます。
本記事では、実際に運用現場で使用できるファイル転送スクリプトを題材に、その構造と使い方を解説します。特に共通関数やログ出力を活用した保守性の高い実装例をベースに、再利用性と安定性を重視した構成としています。
スクリプト全体の目的と構造
このスクリプトの目的は、ある指定ディレクトリからファイルを一括で別サーバーまたは別パスに転送することです。ただし単なる
cp や
scp を使うだけでなく、ログ出力や排他制御、中間ファイルへの一時退避などを通じて、業務処理と連携しやすい形に設計されています。
構造は以下のように分かれています。
処理名 | 説明 |
---|---|
pre-process | 共通関数の読み込み、trap設定、ログ開始 |
main-process | ファイル一覧取得、転送処理 |
post-process | 終了ログ出力、trap解除 |
また、scope変数によって各セクションの明確な切り分けがされています。
前提とするディレクトリ構成
スクリプトの動作には一定のディレクトリ構成が必要です。これはスクリプトの安定性を保ち、ログや一時ファイルの混在を防ぐためです。
ディレクトリ | 役割 |
---|---|
scripts/bin | 実行スクリプト本体を格納 |
scripts/com | 共通関数(logger.shrc、utils.shrc) |
scripts/log | ログ出力ファイル格納先 |
scripts/tmp | 一時作業ファイル格納先 |
scripts/rep | 処理済み退避ファイル格納先 |
この構成はシンプルですが強力です。運用トラブル時もファイルの所在を追いやすくなります。
スクリプトの読み込みと初期処理
スクリプト冒頭では共通関数の読み込みと、ログ出力の初期化、trapの設定などを行います。
. $(dirname "$0")/../com/logger.shrc
. $(dirname "$0")/../com/utils.shrc
startLog
trap "terminate" 0 1 2 3 15
この時点でログが開始され、異常終了時にも自動でログが記録される状態になります。
ファイルの抽出と排他制御
転送対象のファイルは、指定されたディレクトリから find コマンドなどで抽出します。抽出処理では、並列実行や多重起動を防ぐためにロックファイルを用いて排他制御します。
execLock "${LOCK_FILE}" || exit ${JOB_NG}
target_list=$(find "${TARGET_DIR}" -type f -name "*.csv")
このようにして、同時実行によるファイル競合や破損を未然に防ぎます。
ファイルの転送処理
抽出したファイルに対して、rsyncなどで転送処理を実行します。処理ごとにログ出力を行い、正常/異常のステータスをログに記録します。
rsync -av "${file}" "${DEST_DIR}/"
logOut "INFO" "転送成功:${file}"
処理後には退避ディレクトリ(rep)にコピーを残す設計にしておくことで、再送や再処理が容易になります。
終了処理とログ出力
最後にtrapによって定義された終了処理が呼ばれます。この処理ではログの終了記録とロックファイルの解除が行われます。
endLog
この時点でスクリプトの実行は正常終了となります。
まとめと活用方法
このファイル転送スクリプトは、定時バッチ処理やジョブの中継処理として非常に有効です。特に以下のような用途に向いています。
活用場面 | 説明 |
---|---|
帳票ファイルの転送 | 集計後に決まった時間で別システムへ送信 |
監視ログの集約 | 複数サーバーからログを集める場合 |
ステージング環境間のデータ移送 | 一時的なファイル転送が必要なケース |
スクリプトを適切に構成すれば、ただのファイル転送処理を、業務システムの一部として安全に組み込むことができます。運用保守の負担を減らすためにも、ログの整備や構造の明確化は避けて通れません。まずはこのスクリプトをベースに、実運用環境に合わせたカスタマイズを加えることで、強固で再利用可能な転送基盤を構築してください。