こんにちは。よっしーです(^^)
今日は、スクリプトがあるパスを取得する方法についてご紹介します。
背景
bashにおけるスクリプトがあるパスを取得する方法について調査する機会があったので、そのときの内容を備忘として残しました。
この記事のソースは下記のサイトにアップしています。
実行環境について
実行環境は下記の記事を参考にお願いします。
概要
Bashスクリプトが存在するパスを取得する理由はいくつかあります。
- 相対パスの解決:
スクリプトが相対パスで他のファイルやリソースを参照している場合、スクリプトの実行ディレクトリを基準に相対パスを解決する必要があります。スクリプトのパスを取得することで、そのディレクトリを基準にして相対パスを解決することができます。 - 絶対パスの取得:
スクリプトが他のプログラムやスクリプトと連携する場合、そのファイルの絶対パスが必要な場合があります。スクリプトがどのディレクトリにあるかを知ることで、他のプログラムとの連携がスムーズに行えます。 - リソースへのアクセス:
スクリプトが同じディレクトリ内のあるファイルやディレクトリにアクセスする場合、それらのリソースのパスを構築する必要があります。スクリプトのパスを取得することで、そのディレクトリを基準にして他のリソースへのパスを構築できます。 - ログや設定ファイルの配置:
スクリプトがログファイルや設定ファイルを参照する場合、これらのファイルがどのディレクトリに配置されているかを知る必要があります。スクリプトのパスを取得することで、それらのファイルへの正確なパスを構築できます。
これらの理由から、スクリプトが自身のパスを取得することは一般的なプラクティスであり、これによってスクリプトの柔軟性や再利用性が向上します。
修正内容
下記のファイルを使用します。
new file: local/work/17_pwd/17_pwd.sh
new file: local/work/17_pwd/test.sh
new file: local/work/17_pwd/test_ext.sh
17_pwd.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_info '-- $0'
script_path="$(cd "$(dirname "$0")" && pwd)"
log_info "${script_path}"
script_name="$(basename "${0}")"
log_info "${script_name}"
log_info '-- $BASH_SOURCE[0]'
script_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
log_info "${script_path}"
script_name="$(basename "${BASH_SOURCE[0]}")"
log_info "${script_name}"
test.sh
#!/usr/bin/env bash
# shellcheck source=/dev/null
. 17_pwd.sh
test_ext.sh
#!/usr/bin/env bash
pushd ext || exit
# shellcheck source=/dev/null
. ../17_pwd.sh
動作確認
下記のコマンドを実行します。
make build
make up
make login
cd 17_pwd
chmod +x 17_pwd.sh
./17_pwd.sh
下記のような出力になっていれば成功です。
解説
17_pwd.sh
このコードは、Bashスクリプト内でスクリプトのパスとファイル名を取得し、それをログに出力するためのものです。
コードの流れは以下の通りです:
log_info '-- $0'
: ‘– $0’ をログに出力しています。これはスクリプトファイルの$0
の値を表示するものです。script_path="$(cd "$(dirname "$0")" && pwd)"
: スクリプトのディレクトリパスを取得しています。dirname "$0"
はスクリプトのディレクトリを取得し、cd
とpwd
を使ってそのディレクトリの絶対パスを取得しています。結果はscript_path
に格納され、ログにも出力されます。script_name="$(basename "${0}")"
: スクリプトのファイル名を取得しています。basename "${0}"
はパスからファイル名を抽出し、結果はscript_name
に格納され、ログにも出力されます。log_info '-- $BASH_SOURCE[0]'
: ‘– $BASH_SOURCE[0]’ をログに出力しています。これはスクリプトファイルの${BASH_SOURCE[0]}
の値を表示するものです。script_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
:${BASH_SOURCE[0]}
を使用してスクリプトのディレクトリパスを取得し、同様にscript_path
に格納され、ログにも出力されます。script_name="$(basename "${BASH_SOURCE[0]}")"
:${BASH_SOURCE[0]}
を使用してスクリプトのファイル名を取得し、同様にscript_name
に格納され、ログにも出力されます。
これにより、スクリプトの実行中にログにスクリプトのパスやファイル名を出力することができます。
$0
と ${BASH_SOURCE[0]}
の違い
と ${BASH_SOURCE[0]} の違い
$0
と ${BASH_SOURCE[0]}
の違い$0
と ${BASH_SOURCE[0]}
の主な違いは、スクリプトがどのように呼び出されたかに関連しています。
$0
:
$0
は、現在のスクリプトやコマンドが呼び出されたときのコマンドライン引数として使用される変数です。- 通常、シェルスクリプト内で
$0
を使用すると、そのスクリプト自体のファイル名が表示されます。ただし、シェルスクリプトが他のスクリプトから呼び出される場合、呼び出し元のスクリプトのファイル名が表示されることもあります。
# シェルスクリプト内での例
echo "スクリプトのファイル名: $0"
${BASH_SOURCE[0]}
:
${BASH_SOURCE[0]}
は、Bashスクリプト内でそのスクリプトが読み込まれたファイルのパスを表します。- これは、スクリプトが他のスクリプトから呼び出されている場合でも正確にそのスクリプトのパスを取得できる利点があります。
# Bashスクリプト内での例
echo "スクリプトのパス: ${BASH_SOURCE[0]}"
一般的に、${BASH_SOURCE[0]}
を使用する方が、スクリプトが他のスクリプトから呼び出される場合でも正確なスクリプトのパスを取得できるため、柔軟性があります。ただし、${BASH_SOURCE[0]}
は Bash に特有の変数であるため、他のシェルスクリプトとの互換性を考慮する必要があります。
test.shとtest_ext.sh
$0
と ${BASH_SOURCE[0]}
の違いを確認しています。
test.shの実行結果は下記になります。
test_ext.shの実行結果は下記になります。
おわりに
今日は、スクリプトがあるパスを取得する方法についてご紹介しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント