機能説明
サブプロセスを起動し、プログラムのコマンドを実行します。
記述形式
【Windows版】
exec cmd /c cmdname 【args …】 |
注) execコマンドは、cmd /cと併せて使用してください。
【UNIX版】
exec cmdname 【args …】 |
オプション
起動するコマンドファイル名を指定します。Windows上のファイル名の場合は、ディレクトリの区切りを“\”(円記号)のほかに“/”(スラッシュ)で記述することが可能です。円記号を使用する場合は、エスケープ文字に扱われないようファイル名全体を“{ }”(中括弧)で囲む必要があります。
起動するコマンドに渡す引数を指定します。
最後のargsが“&”の場合、コマンドはバックグラウンドで実行されます。コマンドは通常、フォアグラウンドで実行され、execコマンドはcmdnameのプロセス終了を待ちますが、バックグラウンドで実行した場合は、終了を待たずに復帰します。
また、argsにはフロー制御記号を指定することが可能です。
Windowsの場合、ファイルをパス指定で与えるときは、ディレクトリの区切りに“\”(円記号)を使用してファイル名全体を“{ }”(中括弧)で囲む必要があります。
フロー制御
argsに以下のフロー制御記号を記述することで、起動コマンドの標準入出力への操作や複数コマンドを起動しての情報のやりとりが可能となります。
記号・書式 | 意味 | 例 |
---|---|---|
| | パイプライン中の個々のコマンドを区切ります。前のコマンドの標準出力を後のコマンドの標準入力へつなげます。同様にして3つ以上のコマンドをつないでいくことが可能です。 | 【Windows版】 【UNIX版】 |
< filename | cmdnameの標準入力として、filenameで指定したファイルの内容が読み込まれます。(注1) | 【Windows版】 【UNIX版】 |
<< value | cmdnameの標準入力として、valueで指定した値(文字列)が読み込まれます。(注1) | 【Windows版】 【UNIX版】 |
> filename | cmdnameの標準出力がfilenameで指定したファイルに上書きで書き込まれます。(注1) | 【Windows版】 【UNIX版】 |
>& filename | cmdnameの標準出力と標準エラー出力がfilenameで指定したファイルに上書きで書き込まれます。(注1) | 【Windows版】 【UNIX版】 |
2> filename | cmdnameの標準エラー出力がfilenameで指定したファイルに上書きで書き込まれます。(注2) | 【Windows版】 【UNIX版】 |
注1:cmdnameの部分が“|”により複数のコマンドからなる場合、読み込みは先頭のコマンドが、書き込みは末尾のコマンドがその対象となります。
注2:cmdnameの部分が“|”により複数のコマンドからなる場合、すべてのコマンドの標準エラー出力がfilenameで指定したファイルに格納されます。
復帰値
cmdnameコマンドの標準出力が返されます。このとき、出力テキストの末尾にある改行コードは削除されます。
フロー制御により複数のコマンドが実行される場合は、末尾のコマンドがその対象となります。
また、フロー制御により標準出力がリダイレクトされている場合は、空文字列を返します。
起動コマンドのプロセスIDが返されます。
フロー制御により複数のコマンドが実行される場合は、全プロセスIDが空白で区切って返されます。
アプリケーションが出力する標準出力を、execコマンドの復帰値として獲得することはできません。
その他入出力情報
以下の条件の場合、スクリプトは処理例外の発生を検知し強制終了されます。必要に応じてcatchコマンドで処理例外のトラップを行ってください。
コマンドがフォアグラウンドで実行されている、かつ、
コマンドの標準エラー出力がリダイレクトされていない状態でコマンドが標準エラー出力へのメッセージを出力する、または、
コマンドの終了コードが“0”以外である。
catchによる処理例外のトラップをしない場合
【Windows版】
#アプリケーションを起動します。標準出力を変数"outmsg"に格納します。 set outmsg [exec cmd /c {c:\usr\bin\appl001.exe}] #アプリケーションが標準出力へ出力したデータをジョブの標準出力へ出力します。 puts stdout $outmsg #アプリケーションの実行まで正常に完了した場合は、終了コード"0"で終了します。 exit 0
【UNIX版】
#アプリケーションを起動します。標準出力を変数“outmsg”に格納します。 set outmsg [exec /usr/bin/appl001] #アプリケーションが標準出力へ出力したデータをジョブの標準出力へ出力します。 puts stdout $outmsg #アプリケーションの実行まで正常に完了した場合は、終了コード“0”で終了します。 exit 0
注) catchによる処理例外設定がないため、execで起動したコマンドが、“0”以外の終了コードで終了したり、異常終了した場合に以下の問題が発生します。
ジョブの終了コードは“1”となり、実行コマンドの終了コードが採用されない。
実行コマンドが標準エラー出力に出力したエラーメッセージ等を獲得することができない。
これらを回避するために、コマンドを起動する際にはcatchコマンドによる処理例外のトラップをすることを推奨します。
処理例外をcatchコマンドでトラップした場合、以下の情報を参照することができます。
標準出力/標準エラー出力情報(errorInfo)
終了コード(errorCode)
標準出力/標準エラー出力情報(errorInfo)について
コマンドの標準出力/標準エラー出力がリダイレクトされていない場合、グローバル変数errorInfoの先頭にその出力文字列が格納されます。errorInfoには、exec文自身の実行エラーを示す文字列も格納されます。
例:
【Windows版】
以下の仕様のアプリケーション(c:\usr\bin\appl001.exe)がエラー終了した場合
仕様:指定された日付のデータを標準出力に書き込む。 日付の指定が不当な場合は以下のメッセージを標準エラー出力に出力する。 “日付の指定に誤りがあります。yyyymmdd で指定してください。”
if {[catch { exec cmd /c {c:\usr\bin\appl001.exe} 010520 }]} { puts "エラー情報 START" puts $errorInfo puts "エラー情報 END" }
上記を実行すると、標準出力には以下のように表示されます。
エラー情報START 日付の指定に誤りがあります。yyyymmddで指定してください。←appl001コマンドの出力 while executing ← exec文自身の実行エラーを "exec cmd /c {c:\usr\bin\appl001.exe} 010520" ← 示す文字列 エラー情報END
【UNIX版】
存在しないファイル(/tmp/data)を指定し、lsコマンドを実行する場合
if {[catch { exec ls /tmp/data }]} { puts "エラー情報 START" puts $errorInfo puts "エラー情報 END" }
上記を実行すると、標準出力には以下のように表示されます。
エラー情報 START /tmp/data: ファイルもディレクトリもありません。 ← lsコマンドの出力 while executing ← exec文自身の実行エラーを "exec ls /tmp/data" ← 示す文字列 エラー情報 END
終了コード(errorCode)について
コマンドの終了コードが“0”以外の場合は、グローバル変数errorCodeに以下の書式で終了コードが格納されています。また、その他の詳細情報も格納されます。 errorCodeの書式については、“catch(スクリプト行を実行し処理例外をトラップする)”の復帰値を参照してください。
CHILDSTATUS pid exitcode |
【Windows版】
ここに入る数字は意味を持ちません。
【UNIX版】
プロセスID
プロセスの終了コード
実行コマンドの入出力について
実行コマンドのリダイレクトされていない入出力は以下のとおりに扱われます。
入出力 | フォアグラウンド実行 | バックグラウンド実行 |
---|---|---|
標準入力 | スクリプトプロセス自身の標準入力から読み込まれる。 | |
標準出力 | 通常は、execコマンドの戻り値となる。 | スクリプトプロセス自身の標準出力に書き込まれる。 |
標準エラー出力 | execコマンドの処理例外として扱われ、catchでトラップした場合にはerrorInfoに格納される。 | スクリプトプロセス自身の標準エラー出力に書き込まれる。 |
参照
注意事項
子孫プロセスが常駐するコマンドやシェルの起動について
以下の条件をすべて満たした場合、直接起動したコマンドが終了しても復帰しません。
フォアグラウンドでコマンドを起動している。
起動したコマンドがさらに子プロセスを起動している。
標準出力と標準エラー出力をリダイレクトしていない。
したがって、デーモン起動シェルなど常駐するプロセス起動を行う場合は、以下のようにバックグラウンドで起動するか、標準出力と標準エラー出力をファイル等にリダイレクトするようにしてください。
バックグラウンド起動
exec rdbstart & |
標準出力と標準エラー出力をファイルにリダイレクト
exec rdbstart >& /tmp/log.txt |
標準出力と標準エラー出力を無視
exec rdbstart >& /dev/null |
Windowsのコマンドでパラメタの解釈が特殊なコマンドについて【Windows版】
Windowsのプログラムには、コマンドのオプションのダブルクォーテーションなどを特別な文字として解釈する一般的なコマンドと、そういった解釈をしない特殊なコマンドがあります。そのような特殊なコマンドには、スクリプト自身もダブルクォーテーションの解釈を行っているため、パラメタを正しく渡せない場合があります。
一般的なコマンドのパラメタ解釈例
コマンドラインの記述 | コマンド内での解釈 |
---|---|
"abc" | abc |
\"abc\" | "abc" |
特殊なコマンドは、コマンドラインの記述をそのまま解釈します。
特別な文字を解釈しないコマンドを実行させる場合は、コマンドを実行するバッチファイルを作成し、そのバッチファイルをexecで実行するように記述してください。
swctclshの終了について【Windows版】
execから起動したコマンドや、そのコマンドからさらに起動されたプロセスが動作中の間は、swctclshは終了せずに起動中のままになります。
フロー制御記号から始まる引数について
フロー制御記号(< > 2>)から始まる文字列は、引数に指定した場合フロー制御記号として解釈されるため、文字列として渡すことはできません。以下のどちらかの方法で指定してください。
文字列の先頭に半角空白を付加して引数に指定する
文字列として解釈させるために、先頭に半角空白を付加した文字列に変えて引数に指定します。
文字列が変数(msgtxt)に格納されている場合、以下のように記述することで、先頭に半角空白を付加することができます。
if {[regexp {^<|^>|^2>} $msgtxt] == 1} { set msgtxt " $msgtxt" }
シェルスクリプトまたはバッチファイルを利用する
目的のコマンドを起動するシェルスクリプト(UNIX版)またはバッチファイル(Windows版)をスクリプト内で作成し、それをexecコマンドで起動させるようにします。ただし、引数文字列内にダブルクォーテーション(")が含まれていると、シェルスクリプトやバッチファイル内での文字列解釈が正しく行われなくなるため、引数文字列中に含まれるダブルクォーテーションをシングルクォーテーション(')にあらかじめ置き換えます。
例:コマンド(usercmd)の引数に、任意の文字列が格納されている変数(msgtxt)を指定して起動させます。
【UNIX版】
“/tmp/usercmd_tmp.sh”は、一時的に作成するシェルスクリプトで、実行後に削除します。
if {[regexp {^<|^>|^2>} $msgtxt all] == 1} { regsub {"} $msgtxt {'} msgtxt set fd [open /tmp/usercmd_tmp.sh w] puts $fd "usercmd \"$msgtxt\"" close $fd exec sh /tmp/usercmd_tmp.sh exec /usr/bin/rm -f /tmp/usercmd_tmp.sh } else { exec usercmd $msgtxt }
【Windows版】
“c:\temp\usercmd_tmp.bat”は、一時的に作成するバッチファイルで、実行後に削除します。
if {[regexp {^<|^>|^2>} $msgtxt all] == 1} { regsub {"} $msgtxt {'} msgtxt set fd [open {c:\temp\usercmd_tmp.bat} w] puts $fd "usercmd \"$msgtxt\"" close $fd exec {c:\temp\usercmd_tmp.bat} exec cmd /c del {c:\temp\usercmd_tmp.bat} } else { exec usercmd $msgtxt }
使用例
【Windows版】
dirコマンドを実行し、コマンドの標準出力/標準エラー出力をすべてスクリプトの標準出力へ出力させます。
if {[catch { set outmsg [exec cmd /c dir {c:\tmp\data}] # dirの標準出力(exec戻り値)をスクリプトの標準出力へ puts stdout $outmsg }]} { # 処理例外発生 # outmsgには初期値として$errorInfoを格納しておきます。 set outmsg $errorInfo # dirの出力情報(errorInfoの末尾2行を除いたもの)をスクリプトの標準出力へ regexp {(.*)\n.*\n.*} $errorInfo all outmsg puts stdout $outmsg }
【UNIX版】
lsコマンドを実行し、コマンドの標準出力/標準エラー出力をすべてスクリプトの標準出力へ出力させます。
if {[catch { set outmsg [exec ls -l /tmp/data] # lsの標準出力(exec戻り値)をスクリプトの標準出力へ puts stdout $outmsg }]} { # 処理例外発生 # outmsgには初期値として$errorInfoを格納しておきます。 set outmsg $errorInfo # lsの出力情報(errorInfoの末尾2行を除いたもの)をスクリプトの標準出力へ regexp {(.*)\n.*\n.*} $errorInfo all outmsg puts stdout $outmsg }
実行結果/出力形式
標準出力には、以下のように表示されます。
【Windows版】
ファイルc:\tmp\dataが存在する場合
ドライブ C のボリューム ラベルはありません。 ボリューム シリアル番号は 2420-12F3 です c:\tmp のディレクトリ 00/12/01 11:37a 972 data 1 個のファイル 972 バイト 463,110,144 バイトの空き領域
ディレクトリ(ファイル)c:\tmp\dataが存在しない場合
ドライブ C のボリューム ラベルはありません。 ボリューム シリアル番号は 2420-12F3 です c:\tmp のディレクトリ ファイルが見つかりません
【UNIX版】
ファイル/tmp/dataが存在する場合
-rw-rw-r-- 1 root other 0 9月 25日 15:05 /tmp/data
ファイル(ディレクトリ)/tmp/dataが存在しない場合
/tmp/data: ファイルもディレクトリもありません。