よっしー
こんにちは。よっしーです(^^)
今日は、bashにおけるxargsを利用した関数の並列実行についてご紹介します。
背景
bashにおけるxargsを利用した関数の並列実行について調査する機会があったので、そのときの内容を備忘として残しました。
この記事のソースは下記のサイトにアップしています。
実行環境について
実行環境は下記の記事を参考にお願いします。
概要
本記事では、xargsを利用した関数の並列実行をしています。元となるソースは、前回記事のロギングのコードを利用しています。
作成ファイル一覧
下記のファイルを作成しました。
new file: local/work/13_xargs/13_xargs.sh
13_xargs.sh
#!/usr/bin/env bash
set -euCo pipefail
ESC="$(printf '\033')" # \e や \x1b または $'\e' は使用しない
LOG_OUT=./stdout.log
LOG_ERR=./stderr.log
readonly ESC LOG_OUT LOG_ERR
exec 1> >(tee -a "$LOG_OUT")
exec 2> >(tee -a "$LOG_ERR")
function log_info() {
local log_msg
log_msg=$(gen_log_msg '32' 'INFO' "$*")
echo "${log_msg}"
}
function log_debug() {
local log_msg
log_msg=$(gen_log_msg '34' 'DEBUG' "$*")
echo "${log_msg}"
}
function log_warn() {
local log_msg
log_msg=$(gen_log_msg '33' 'WARN' "$*")
echo "${log_msg}"
}
function log_err() {
local log_msg
log_msg=$(gen_log_msg '31' 'ERROR' "$*")
echo "${log_msg}" >&2
}
function gen_log_msg() {
local prefix
prefix=$(printf "${ESC}[%dm%5s${ESC}[m\n" "$1" "$2" )
printf "%s\t[%s]\t%s" "$(date '+%Y/%m/%d %H:%M:%S.%3N')" "$prefix" "$3"
}
function trap_err() {
error_status=$?
msg=$(printf "エラー発生 \$?=%d %s %s:%d" ${error_status} "${BASH_SOURCE[0]}" "${FUNCNAME[1]}" ${BASH_LINENO[0]})
log_err "${msg}"
}
function trap_exit() {
msg=$(printf "終了時の処理 %s %s:%d" "${BASH_SOURCE[0]}" "${FUNCNAME[1]}" ${BASH_LINENO[0]})
log_debug "${msg}"
}
function poc_run() {
log_info "poc $1"
}
trap trap_err ERR
trap trap_exit EXIT
log_debug "$(which bash)"
log_debug "$(bash --version)"
export -f poc_run log_info log_err gen_log_msg
seq 1 20 | xargs -P "$(nproc)" -I{} bash -c "poc_run {}"
# 標準エラーへの出力確認用
ls dummy.txt
echo "ここは表示されない"
動作確認
下記のコマンドを実行します。
make build
make up
make login
cd 13_xargs
chmod +x 13_xargs.sh
./13_xargs.sh
下記のような出力になることを想定しています。
解説
13_xargs.sh
このBashスクリプトは、ログ出力とエラーハンドリングを含むサンプルのシェルスクリプトです。以下に、各部分の解説を行います。
#!/usr/bin/env bash
: スクリプトのシバン行。これは、このスクリプトがBashで実行されることを示しています。set -euCo pipefail
: スクリプトのオプションの設定です。
-e
: エラーが発生した場合にスクリプトを即座に終了します。-u
: 未定義の変数が使用された場合にエラーとして扱います。-o pipefail
: パイプの途中でエラーが発生した場合にもスクリプトを終了します。
ESC="$(printf '\033')"
: ANSIエスケープシーケンスを表す変数ESC
を定義しています。LOG_OUT=./stdout.log
およびLOG_ERR=./stderr.log
: 標準出力と標準エラー出力のログファイルのパスを定義しています。readonly ESC LOG_OUT LOG_ERR
:ESC
,LOG_OUT
,LOG_ERR
を読み取り専用に設定します。exec 1> >(tee -a "$LOG_OUT")
およびexec 2> >(tee -a "$LOG_ERR")
: 標準出力および標準エラー出力をそれぞれtee
コマンドにパイプし、ログファイルに追記するように設定します。- ログ関数:
log_info
,log_debug
,log_warn
,log_err
: 指定されたメッセージに応じたログメッセージを生成し、それを標準出力または標準エラー出力に出力します。gen_log_msg
: ログメッセージのプレフィックスを生成します。
trap_err
およびtrap_exit
: エラーおよびスクリプト終了時に実行されるトラップ関数。エラーメッセージや終了時のメッセージをログに記録します。poc_run
: サンプルの関数。引数として渡された値をもとにログメッセージを生成します。trap trap_err ERR
およびtrap trap_exit EXIT
: エラーおよびスクリプト終了時に対応するトラップ関数を設定します。log_debug "$(which bash)"
およびlog_debug "$(bash --version)"
: Bashの実行パスとバージョン情報をデバッグログに出力します。export -f poc_run log_info log_err gen_log_msg
: サブシェルで実行されるコマンドで関数を利用できるように関数をエクスポートします。seq 1 20 | xargs -P "$(nproc)" -I{} bash -c "poc_run {}"
: 1から20までの数字を生成し、それを複数のプロセスで同時に処理します。各プロセスはpoc_run
関数を呼び出して、対応する数値を引数として渡します。ls dummy.txt
: 標準エラー出力への出力を確認するためのダミーコマンド。エラーを意図的に発生させます。echo "ここは表示されない"
: 上記のls dummy.txt
でエラーが発生した場合、この行以降のコードは実行されません。エラーがない場合は、このメッセージが表示されます。
おわりに
今日は、bashにおけるlogging(ロギング)についてご紹介しました。
よっしー
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント