5.1.4 関数
同じジョブ定義スクリプトファイル内や外部ファイルに関数を定義すると使用できます。関数を定義する場合の書式を次に示します。
- 書式1
関数名() { command : (略) }
- 書式2
function 関数名 { command : (略) }
関数名の命名規則は変数と同じです。また,シェル標準コマンド,シェル拡張コマンド,および次のコマンド名と同名の関数は定義できません。
-
bg
-
bind
-
fc
-
fg
変数の命名規則については,「(1) 変数の命名規則」を参照してください。
関数を実行するジョブ定義スクリプトと異なるファイルに定義した場合,関数を実行する前に.(ドット)コマンド,または#-adsh_scriptコマンドで関数を定義したジョブ定義スクリプトを呼び出す必要があります。
書式を次に示します。.(ドット)コマンドについては,「9.3 シェル標準コマンド」の「.コマンド(シェルスクリプトを実行する)」,#-adsh_scriptコマンドについては,「9.5 スクリプト拡張コマンド」の「#-adsh_scriptコマンド(実行中のジョブ定義スクリプトから外部のジョブ定義スクリプトファイルを呼び出す)」を参照してください。
. 関数を定義したファイル名
または
#-adsh_script 関数を定義したファイル名
ジョブ定義スクリプト内で定義した関数の名称が,同一ジョブ定義スクリプト内,.(ドット)コマンドで呼び出したジョブ定義スクリプト内,または#-adsh_scriptコマンドで呼び出したジョブ定義スクリプト内で定義したほかの関数と重複していた場合,関数を実行する位置の直前に定義された関数が実行されます。
関数を実行する場合の書式を次に示します。関数には引数を指定できます。指定した引数は関数内では位置パラメーター$1以降に格納されます。
関数名 [args]
なお,関数内の位置パラメーター$0には,書式に応じて次の内容が格納されます。
書式1で定義した関数の場合,シェルスクリプト名称が格納される。
書式2で定義した関数の場合,関数名が格納される。
関数の引数の指定有無と位置パラメーターの関係を次の表に示します。
関数呼び出し元の位置パラメーター |
関数の引数 |
関数開始時の位置パラメーター |
関数からの回復時の位置パラメーター |
---|---|---|---|
指定あり |
指定あり |
引数に指定された値 |
関数呼び出し元の位置パラメーターの値 |
指定あり |
指定なし |
値なし |
関数呼び出し元の位置パラメーターの値 |
指定なし |
指定あり |
引数に指定された値 |
値なし(関数呼び出し元の位置パラメーターの値) |
指定なし |
指定なし |
値なし |
値なし(関数呼び出し元の位置パラメーターの値) |
- 〈この項の構成〉
(1) 関数内ローカル変数
Advanced Shellでは,関数内でtypesetコマンドを使用して変数を定義すると,関数内で有効なローカル変数を定義できます。定義した変数は,関数が完了した時点で関数実行前の状態に回復されます。関数内ローカル変数の実行例を次に示します。
- ジョブ定義スクリプトの内容
0001 : myfunc(){ # 関数myfuncの定義 0002 : typeset -r var=abc # 関数内ローカル変数にvarを読み込みで定義 0003 : echo $var # 変数varの値を出力 0004 : readonly -p # 読み込み専用属性の変数を出力 0005 : return 0 0006 : } 0007 : typeset -i var=123 # 変数varを整数型で定義 0008 : typeset | grep var # 変数varの属性を出力 0009 : myfunc # 関数myfuncを実行 0010 : echo $var # 関数実行後の変数varの値を出力 0011 : readonly -p # 読み込み専用属性の変数を出力 0012 : typeset | grep var # 変数varの属性を出力 0013 : exit 0 0014 :
- 実行ジョブのSTDOUTファイルの内容
-
******** 実行ジョブのSTDOUTファイルの内容 ******** typeset -i var ←8行目の結果。変数varは整数型で定義済み abc ←3行目の結果。変数varはabcに更新 readonly var=abc ←4行目の結果。変数varは読み込み専用属性 readonly ADSH_DIR_BIN=/opt/jp1as/bin/ readonly ADSH_DIR_CMD=/opt/jp1as/cmd/ readonly ADSH_DIR_PARTS_EN=/opt/jp1as/parts/en/ readonly ADSH_DIR_PARTS_JA=/opt/jp1as/parts/ja/ 123 ←10行目の結果。関数完了後,変数varの値は回復 readonly ADSH_DIR_BIN=/opt/jp1as/bin/ readonly ADSH_DIR_CMD=/opt/jp1as/cmd/ readonly ADSH_DIR_PARTS_EN=/opt/jp1as/parts/en/ readonly ADSH_DIR_PARTS_JA=/opt/jp1as/parts/ja/ typeset -i var ←12行目の結果。8行目の出力結果と同じ
(2) トレースモード
関数のトレースモードを有効にすることで,関数に記述されたコマンドを実行すると同時にコマンドの内容を標準エラー出力に出力できます。
関数のトレースモードへの切り替えはシェル標準コマンドのtypesetコマンドで実行します。typesetコマンドについては,「9.3 シェル標準コマンド」の「typesetコマンド(変数や関数の属性と値を明示的に宣言する)」を参照してください。
例として,typesetコマンドの指定内容と,標準エラー出力への出力結果を次に示します。
- ジョブ定義スクリプトの内容
0001 : fn(){ 0002 : echo "--- `date`" 0003 : } 0004 : typeset -ft fn 0005 : fn
- 関数のトレースモードによる標準エラー出力への出力結果
-
+ date + echo --- 2023年 5月 18日 木曜日 09:58:14 JST
(3) 関数のオートロード機能
関数のオートロード機能を使用すると,実行するシェルスクリプト内で使用する関数だけが実行時に定義されます。オートロード機能を使用しない場合と比べて,共通化された関数が実行有無に関係なく一度に実行されることがなくなるため,バッチジョブの実行性能が向上します。
関数のオートロード機能を使用する手順は次のとおりです。
関数を定義したファイル(関数定義ファイル)を作成し,関数名と同じファイル名で保存する。
関数定義ファイル内に複数の関数を定義した場合,記述したすべての関数が定義されます。そのため,関数定義ファイルで定義した関数名がすでに定義されている関数と重複していた場合,関数の定義内容が上書きされるため,注意してください。
なお,関数定義ファイル内にコマンドなど関数定義以外の内容を記述した場合は,外部スクリプトと同等に動作します。
ジョブ定義スクリプトに次のコマンドを指定して,関数のオートロード機能を有効にする。
typeset -fu 関数名 [関数名2...]
関数名には,関数定義ファイル名と同じ名前の関数を指定します。
また,Advanced Shellでは「typeset -fu」コマンドの別名としてautoloadを提供します。autoloadの形式は次のとおりです。
autoload 関数名 [関数名2...]
typesetコマンドについては,「9.3 シェル標準コマンド」の「typesetコマンド(変数や関数の属性と値を明示的に宣言する)」を参照してください。
autoloadについては,「5.1.5 コマンドの別名定義」を参照してください。
シェル変数FPATHに,関数定義ファイルを格納したディレクトリを指定する。
オートロード機能を有効にした関数が関数定義ファイルに定義されていない場合,シェル変数FPATHに指定されたディレクトリから関数名と一致する関数定義ファイルの内容を読み込んで,記述されているすべての関数を定義します。シェル変数FPATHは,ジョブ定義スクリプトおよび環境ファイルで指定できます。
(a) オートロード機能の使用例(typeset -fuコマンドを使用した場合)
typeset -fuコマンドを使用した関数のオートロード機能の使用例を次に示します。なお,Advanced Shellではtypeset -fuコマンドのエイリアスとしてautoloadを提供しています。この例では関数auto1,関数auto2,関数auto3に対してオートロード機能を実行しています。
- 関数定義ファイル(/home/user001/autoload/auto1)の内容
0001 : function auto1 { # 関数auto1の定義 0002 : echo "start auto1 in FPATH file" 0003 : return 11 0004 : }
- 関数定義ファイル(/home/user001/autoload/auto2)の内容
0001 : autoxx() { # 関数autoxxの定義(auto2は定義しない) 0002 : echo "start autoxx in FPATH file" 0003 : return 255 0004 : }
- /home/user001/autoloadディレクトリの関数定義ファイル
auto1
auto2
(関数定義ファイル「auto3」は存在しない)
- ジョブ定義スクリプト(/home/user001/test.ash)の内容
0001 : export FPATH="/home/user001/autoload" # FPATHの設定 0002 : 0003 : typeset -fu auto1 auto2 # 関数auto1,auto2にオートロード機能を適用 0004 : autoload auto3 # 関数auto3にオートロード機能を適用 0005 : 0006 : auto1 # 関数auto1を実行 0007 : auto2 # 関数auto2を実行 0008 : auto3 # 関数auto3を実行
- 実行結果
******** ジョブコントローラのメッセージ出力 ******** 14:58:04 002117 KNAX0091-I ADSH002117 ジョブが開始しました。 14:58:04 002117 KNAX7901-I ジョブコントローラは,ジョブ終了時にすべての非同期実行プロセスの完了を待ちます。 14:58:04 002117 KNAX7902-I ジョブコントローラは,"端末入力モード"で動作します。 14:58:04 002117 KNAX6112-I コマンド(export, 行番号=1)が正常終了しました。rc=0 E-Time=0.000s C-Time=0.000s 14:58:04 002117 KNAX6112-I コマンド(typeset, 行番号=3)が正常終了しました。rc=0 E-Time=0.000s C-Time=0.000s 14:58:04 002117 KNAX6112-I コマンド(typeset, 行番号=4)が正常終了しました。rc=0 E-Time=0.000s C-Time=0.000s 14:58:04 002117 KNAX6112-I コマンド(echo, 行番号=2)が正常終了しました。rc=0 E-Time=0.000s C-Time=0.000s 14:58:04 002117 KNAX6112-I コマンド(return, 行番号=3)が正常終了しました。rc=11 E-Time=0.000s C-Time=0.000s※1 14:58:04 002117 KNAX6046-E 関数("auto2")が関数定義ファイル("/home/user001/autoload/auto2")内に定義されていません。filename="/home/user001/autoload/test.ash" line=7※2 14:58:04 002117 KNAX6044-E シェル変数FPATHに指定されたディレクトリに関数("auto3")の定義ファイルが見つかりません。filename="/home/user001/autoload/test.ash" line=8※3 14:58:04 002117 KNAX0101-E ADSH002117 ジョブを実行中にエラーが発生しました。 14:58:04 002117 KNAX0098-I ADSH002117 ジョブが終了しました。rc=127 E-Time=0.002s C-Time=0.010s ******** ジョブ定義スクリプトの内容 ******** ***** /home/user001/autoload/test.ash ***** 0001 : export FPATH="/home/user001/autoload" # FPATHの設定 0002 : 0003 : typeset -fu auto1 auto2 # 関数auto1,auto2にオートロード機能を適用 0004 : autoload auto3 # 関数auto3にオートロード機能を適用 0005 : 0006 : auto1 # 関数auto1を実行 0007 : auto2 # 関数auto2を実行 0008 : auto3 # 関数auto3を実行 ***** パス変換情報 ***** ******** 実行ジョブのSTDERRファイルの内容 ******** KNAX0101-E ADSH002117 ジョブを実行中にエラーが発生しました。 KNAX0098-I ADSH002117 ジョブが終了しました。rc=127 E-Time=0.002s C-Time=0.010s ******** ジョブステップの出力 ******** KNAX6380-I ルートジョブのスプールジョブディレクトリにジョブ名を付加します。spool job directory="/var/opt/jp1as/spool/002117-ADSH002117/" KNAX7999-I ルートジョブのジョブコントローラがバッチジョブを終了しました。rc=127
- 注※1
関数auto1の実行結果が正常終了であることを示します。
- 注※2
関数auto2は,FPATHに指定されたディレクトリに同名の関数定義ファイルが存在していますが,その関数定義ファイルに関数auto2の定義がないため,KNAX6046-Eメッセージを出力しエラー終了します。
- 注※3
関数auto3は,FPATHに指定されたディレクトリに同名の関数定義ファイルが存在しないため,KNAX6044-Eメッセージを出力しエラー終了します。
(b) 注意事項
オートロード機能で関数定義ファイルを読み込んで定義された関数は,それ以降,同じファイル名の関数定義ファイルを読み込みません。ただし,unsetコマンドで無効化したあとに関数を再実行した場合は,同名の関数定義ファイルを読み込みます。
オートロード機能を有効にした関数であっても,すでに同一シェルスクリプト内,.(ドット)コマンドで呼び出したシェルスクリプト内,またはスクリプト拡張コマンド#-adsh_scriptで呼び出したシェルスクリプト内で定義済みであれば,関数定義ファイルを読み込みません。
同名の関数を異なる関数定義ファイルに定義した場合,あとで定義された関数が有効になります。関数定義ファイルに複数の関数を定義する場合は,関数名が重複していないか確認してください。
関数「fn1」を異なる関数定義ファイルに定義した例と,その場合の出力結果を次に示します。
関数定義ファイル(/home/user001/autoload/fn1)の内容
0001 : fn1(){ # 関数fn1の定義1 0002 : echo "start fn1" 0003 : return 1 0004 : }
関数定義ファイル(/home/user001/autoload/fn2)の内容
0001 : fn2(){ # 関数fn2の定義 0002 : echo "start fn2" 0003 : return 2 0004 : } 0005 : fn1(){ # 関数fn1の定義2 0006 : echo "start fn1 in fn2" 0007 : return 21 0008 : }
ジョブ定義スクリプト(/home/user001/test.ash)の内容
0001 : export FPATH="/home/user001/autoload" # FPATHの設定 0002 : typeset -fu fn1 fn2 # 関数fn1,fn2のオートロード機能を有効にする 0003 : fn1 # 関数fn1を実行 0004 : fn2 # 関数fn2を実行 0005 : fn1 # 関数fn1を再度実行
標準出力への出力結果
start fn1 ←定義1のfn1が実行されます start fn2 start fn1 in fn2 ←定義2のfn1が実行されます
定義されていない関数に対して,オートロード機能を有効にした場合,関数定義ファイルが読み込まれるまで未定義状態となります。そのため,CUIデバッガのinfo functionsコマンドで表示されません。