前へ | 次へ | 目次 | 索引 |
場合分け文は,特殊な形式の条件コードであり,変数または式の値に応じて,一連のコマンド・ブロックの中の 1 つのブロックだけを実行します。普通,場合分け文で有効な値は,それぞれのコマンド・ブロックの先頭にあるラベルです。場合分け文は,指定された値を GOTO 文のターゲット・ラベルとして使用することによって,該当するコード・ブロックに制御を渡します。
場合分け文を作成するには,次のようにします。
ラベルをリストするには,スラッシュ(または,区切り文字として選択した文字)で区切られたラベルのリストが入っている文字列をシンボルに定義します。このシンボル定義はコマンド・ブロックの前に置かなくてはなりません。
次の例は,COMMAND_LIST シンボルをラベル PURGE,DELETE,EXIT と同じにしています。
$ COMMAND_LIST = "/PURGE/DELETE/EXIT/" |
場合分け文を作成するには,次の手順に従ってください。
手順 | 操作 |
---|---|
1 | INQUIRE コマンドを使用して場合分け変数の値を得る。 |
2 | IF コマンドと一緒にF$LOCATE と F$LENGTH を使用して,場合分け変数の値が有効かどうかを判別する。 |
3 | 場合分け変数が有効な場合には,場合分け文(GOTO コマンド)を実行して,該当するコード・ブロックに制御を渡す。 場合分け変数が有効でない場合は,メッセージを表示して処理を終了するか,別の場合分け値を要求する。 |
次の例では,ラベルが完全なコマンド名に定義されています。したがって,F$LOCATE は,コマンド名の検索文字列の中に区切り文字を含めて,コマンドが短縮されないようにしています。
$GET_COMMAND: $ INQUIRE COMMAND - "Command(EXIT,PURGE,DELETE)" $ IF F$LOCATE("/"+COMMAND+"/",COMMAND_LIST).EQ. - F$LENGTH(COMMAND_LIST)THEN GOTO ERROR_1 $ GOTO 'COMMAND' . . . $ERROR_1: $ WRITE SYS$OUTPUT "No such command as ''COMMAND'." $ GOTO GET_COMMAND |
それぞれのコマンド・ブロックには,1 つ以上のコマンドを指定できます。コマンド・ブロックの先頭には固有のラベルを付けます。それぞれのコマンド・ブロックを終わるときには,コマンド・ブロックのリストにないラベルに制御を渡します。
次の例では,それぞれのコマンド・ブロックに,1つ以上のコマンドを指定しています。コマンド・ブロックの先頭には固有のラベルを付けます(PURGE:, DELETE:)。それぞれのコマンド・ブロックを終わるときには,コマンド・ブロックのリストにないラベル(GOTO GET_COMMAND)に制御を渡します。
$GET_COMMAND: . . . $PURGE: $ INQUIRE FILE $ PURGE 'FILE' $ GOTO GET_COMMAND $ ! $DELETE: $ INQUIRE FILE $ DELETE 'FILE' $ GOTO GET_COMMAND $ ! $EXIT: |
コマンド・ブロックの先頭に,変数をテストするループを作成できます(第 13 章 を参照)。しかし,次の操作を実行すれば,ループの最後に終了変数をテストするループを作成することもできます。
手順 | 操作 |
---|---|
1 | ループを開始する。 |
2 | ループ本体の中のコマンドを実行する。 |
3 | 終了変数を変更する。 |
4 | 終了変数をテストする。 条件が満足されない場合は,ループの始めに戻る。 |
5 | ループを終了する。 |
ループの終わりにある終了変数をテストする場合は,終了変数の中の値にかかわらず,ループ本体のコマンドが少なくとも 1 回は実行されます。
次の 2 つの例は,COMMAND が "EX"(EXIT)に定義されたときに終了するループを実行します。F$EXTRACT は COMMAND を最初の 2 文字に切り捨てます。最初の例では,終了変数の COMMAND がループの始めにテストされ,2 番目の例では,ループの終わりでテストされます。
$ ! EXAMPLE 1 $ ! $GET_COMMAND: $ INQUIRE COMMAND- "Command(EXIT,DIRECTORY,TYPE,PURGE,DELETE,COPY)" $ COMMAND = F$EXTRACT(0,2,COMMAND) $ IF COMMAND .EQS. "EX" THEN GOTO END_LOOP . . . $ GOTO GET_COMMAND $END_LOOP: |
$ ! EXAMPLE 2 $ ! $GET_COMMAND: $ INQUIRE COMMAND- "Command(EXIT,DIRECTORY,TYPE,PURGE,DELETE,COPY)" $ COMMAND = F$EXTRACT(0,2,COMMAND) . . . $ IF COMMAND .NES. "EX" THEN GOTO GET_COMMAND $ ! End of loop |
ループを一定回数実行するには,終了変数としてカウンタを使用します。次の例では,ユーザによって入力された 10 個のファイル名がローカル・シンボル FIL1,FIL2,...,FIL10 に収められます。
$ NUM = 1 ! Set counter $LOOP: ! Begin loop $ INQUIRE FIL'NUM' "File" ! Get file name $ NUM = NUM + 1 ! Update counter $ IF NUM .LT. 11 THEN GOTO LOOP ! Test for termination $END_LOOP: ! End loop . . . |
次の例は,カウンタを使用してループの実行回数を制御します。この例では,ループは 10 回実行されます。終了変数はループの終わりにテストされます。
$! Obtain 10 file names and store them in the $! symbols FILE_1 to FILE_10 $! $ COUNT = 0 $ LOOP: $ COUNT = COUNT + 1 $ INQUIRE FILE_'COUNT' "File" $ IF COUNT .LT. 10 THEN GOTO LOOP $! $ PROCESS_FILES: . . . |
COUNT シンボルを使用してループの中のコマンドの実行回数を記録します。また,シンボル名 FILE_1,FILE_2 から FILE_10 までを作成するのにも COUNT を使用しています。COUNT の値が増分されるのはループの始めですが,テストされるのはループの終わりであることに注意してください。したがって,COUNT が 9 から 10 に増分されると,IF 文が偽の結果を検出する前にループがもう 1 回だけ実行されます(FILE_10 の値を得ます)。
一連の値に対してループを実行するには,F$ELEMENT レキシカル関数を使用します。F$ELEMENT 関数は,区切り文字によって区切られた項目リストから項目を取り出します。F$ELEMENT の引数として項目番号,項目区切り文字,リストを指定しなければなりません。
F$ELEMENT レキシカル関数の使用方法についての詳細は,『OpenVMS DCL ディクショナリ』を参照してください。
次の例では,ファイル CHAP1,CHAP2,CHAP3,CHAPA,CHAPB,CHAPC が順に処理されます。
$ FILE_LIST = "1,2,3,A,B,C" $ INDEX = 0 $PROCESS: $ NUM = F$ELEMENT(INDEX,",",FILE_LIST) $ IF NUM .EQS. "," THEN GOTO END_LOOP $ FILE = "CHAP''NUM'" $ ! process file named by FILE . . . $ INDEX = INDEX + 1 $ GOTO PROCESS $END_LOOP: $ EXIT |
次のコマンド・プロシージャは,ループを使用して,FILE_LIST シンボルにリストされたファイルを別のノードのディレクトリにコピーします。
$ FILE_LIST = "CHAP1/CHAP2/CHAP3/CHAP4/CHAP5" $ NUM = 0 $! $! Process each file listed in FILE_LIST $ PROCESS_LOOP: $ FILE = F$ELEMENT(NUM,"/",FILE_LIST) $ IF FILE .EQS. "/" THEN GOTO DONE $ COPY 'FILE'.MEM MORRIS::DISK3:[DOCSET]*.* $ NUM = NUM + 1 $ GOTO PROCESS_LOOP $! $ DONE: $ WRITE SYS$OUTPUT "Finished copying files." $ EXIT |
F$ELEMENT レキシカル関数から戻される最初のファイルは CHAP1 であり,次のファイルは CHAP2 です。以下も同様です。ループを実行するたびに,NUM の値が増分されるため,次のファイル名が入手されます。F$ELEMENT がスラッシュを戻した場合には,FILE_LIST のすべての項目が処理されたため,ループは終了します。
14.20 PIPE コマンドの使用
PIPE コマンドを使用すると,同一コマンド行から 1 つまたは複数の DCL コマンドを実行できます。これにより,コマンドのパイプライン処理,入出力のリダイレクト,条件実行,バックグラウンド処理など,UNIX 形式のコマンドを処理できるようになります。
このようなコマンド処理の形式は,インターネット・ソフトウェアの開発や使用をサポートします。インターネット・ソフトウェアでは,ホスト・システムとターゲット・システムの両方で存在を解析する,パイプライン・コマンドの使用を前提にしています。
これ以降の節では,PIPE コマンドへの割り込み方法,サブプロセスの性能を向上させる方法など,DCL コマンドの実行以外の目的で PIPE コマンドを使用する方法を説明します。
PIPE コマンドについての詳細は,『OpenVMS DCL ディクショナリ: N--Z』を参照してください。
1 つの PIPE コマンドに,複数の DCL コマンドを指定できます。指定した DCL コマンドは,順番に実行されます。次の形式を使用します。
PIPE command-sequence ; command-sequence [; command-sequences]... |
14.20.1 条件コマンド実行のための PIPE コマンドの使用
先行するコマンド・シーケンスの実行結果により,次のコマンド・シーケンスが実行されます。
PIPE command-sequence1 && command-sequence2 |
command-sequence1 が成功した時のみ, command-sequence2 が実行される点に注意してください。次の形式を使用すると,command-sequence1 が失敗した時のみ command-sequence2 が実行されます。
PIPE command-sequence1 || command-sequence2 |
14.20.2 パイプライン実行のための PIPE コマンドの使用
パイプラインは,縦線(|)区切り文字で表されるパイプで接続されたパイプライン・セグメント・コマンドのシーケンスです。パイプライン・セグメント・コマンドとは,パイプライン内の DCL コマンドです。パイプはパイプライン・セグメント・コマンドの SYS$OUTPUT を,次のコマンドの SYS$INPUT に接続します。パイプラインの形式を次に示します。
PIPE pipeline-segment-command | pipeline-segment-command [|...] |
各パイプライン・セグメント・コマンドは,SYS$OUTPUT を次のパイプライン・セグメント・コマンドの SYS$INPUT に接続し,別々のサブプロセスで実行されます。これらのサブプロセスはパラレルに実行されます。ただし,最初のパイプライン・セグメント・コマンドを除く各パイプライン・セグメント・コマンドが,その先行パイプライン・セグメント・コマンドの標準出力をその標準入力として読み込む程度に同期化されます。最後のパイプライン・セグメント・コマンドが終了すると,パイプラインは実行を終了します。
通常,パイプラインでは "フィルタ・アプリケーション" を使用します。フィルタ・アプリケーションとは,SYS$INPUT からのデータを取り,指定した方法でデータを変換し,それを SYS$OUTPUT に書き込むプログラムのことです。
パイプラインのコンテキストでは,DCL の機能は一部異なります。次に例を示します。
サブプロセスの SYS$COMMAND は,通常,その SYS$INPUT(コマンド・プロシージャが関係しない場合)と同じです。ただしパイプラインでは,サブプロセスの SYS$COMMAND は,先行するパイプ(パイプライン・セグメント・コマンドの SYS$INPUT)ではなく,親プロセスの SYS$COMMAND に設定されます。
パイプライン・セグメント・コマンドは,パイプとの読み込みと書き込みに,RMS 順編成ファイル・アクセス方法しか使用できません。一部の OpenVMS ユーティリティは,順次アクセス以外の方法を使用して,入力ファイルや出力ファイルにアクセスすることがあります。これらの操作は,パイプラインではサポートされていないので失敗します。次の例を参照してください。
$ PIPE CC/NOOBJ/NOLIS TEST.C | SEARCH SYS$INPUT/WIND=(1,1)"%cc-w-" %SEARCH-F-RFAERR, RMS error using RFA access -RMS-F-RAC, invalid record access mode |
この例では,SEARCH コマンドに /WINDOW 修飾子を指定して実行するためには,相対編成ファイル・アクセス方法が必要です。
DCL がシンボルを置換する順序に注意してください。シンボルの置換は,コマンド処理の第 1 フェーズで行われます。PIPE コマンドの一部としてシンボルを定義した場合,DCL は,シンボルを置換してから,そのシンボルが実際に定義されているコマンドを実行しようとします。シンボルの置換を遅延させるには,アンパサンド(&)を使用します。詳細は,第 12.12.2 項 を参照してください。
ほとんどの場合,パイプからの入力は,SYS$INPUT からデータを読み込むことにより取得できます。ただし,コマンド・プロシージャがパイプライン・セグメント・コマンドとして起動される場合は,SYS$INPUT はコマンド・プロシージャ・ファイルにリダイレクトされます。コマンド・プロシージャの中でパイプからデータを取得するには,論理名 SYS$PIPE を使用できます。
次に,パイプライン DCL アプリケーション例 TEE.COM を示します。
$ ! TEE.COM - command procedure to display/log data flowing through $ ! a pipeline $ ! Usage: @TEE log-file $ $ OPEN/WRITE tee_file 'P1' $ LOOP: $ READ/END_OF_FILE=EXIT SYS$PIPE LINE $ WRITE SYS$OUTPUT LINE ! Send it out to the next stage of the pipeline $ WRITE tee_file LINE ! Log output to the log file $ GOTO LOOP $ EXIT: $ CLOSE tee_file $ EXIT |
TEE.COM を使用して,次の PIPE コマンドを入力します。
$ PIPE SHOW SYSTEM | @TEE showsys.log | SEARCH SYS$INPUT LEF |
コマンド・プロシージャ TEE.COM は,パイプラインを流れるデータを記録します。データは,SYS$INPUT ではなく SYS$PIPE から読み込まれます。
パイプラインでは,PIPE コマンドを入力する前に SET VERIFY=IMAGE コマンドを実行した場合でも,省略時の設定でイメージのチェックはオフになっています。これにより,データ・レコードが重複してパイプラインを通過しないようになります。
パイプラインでのイメージのチェックをオンにするには,パイプライン・セグメント・コマンドの前に明示的に SET VERIFY=IMAGE コマンドを使用しなければなりません。この場合,次のようにサブシェルを使用できます。
$ PIPE ... |(SET VERIFY=IMAGE ; ...) | ... |
14.20.3 サブシェル実行のための PIPE コマンドの使用
サブシェルは,区切り文字で区切られ,括弧で囲まれた 1 つまたは複数のコマンド・シーケンスです。サブシェルの形式を次に示します。
PIPE (command-sequence [separator command-sequence]...) |
サブシェル内のコマンド・シーケンスは,サブプロセス環境で実行されます。DCL は,サブシェルが終了してから,次のコマンド・シーケンスを実行します。()区切り文字は,SPAWN/WAIT コマンドに似ています。
この形式の PIPE コマンドを使用するときには,シンボルの置換の扱いに注意してください。シンボルを定義した後,そのシンボルを使用するときには,シンボルの前にアンパサンド(&)を付けてシンボルの置換を遅延させます。アンパサンドを付けなかった場合,シンボルの置換はコマンド処理の第 1 フェーズで行われ,シンボルの定義が信頼できないものになります。
14.20.4 バックグラウンド実行のための PIPE コマンドの使用
コマンド・シーケンスは,次の形式を使用してサブプロセス環境で実行されます。
PIPE command-sequence [ separator command-sequence]... & |
DCL は,コマンド・シーケンスの終了を待ちません。バックグラウンド・サブプロセスが作成されると,制御は DCL に戻ります。
14.20.5 入出力リダイレクトのための PIPE コマンドの使用
コマンド・シーケンスは,次のようにコマンドの実行中に,SYS$INPUT,SYS$OUTPUT,または SYS$ERROR をファイルにリダイレクトできます。
PIPE command-sequence < redirected-input-file |
PIPE command-sequence > redirected-output-file |
PIPE command-sequence 2> redirected-error-file |
パイプライン・セグメント・コマンドも,SYS$INPUT,SYS$OUTPUT,または SYS$ERROR をリダイレクトできます。ただし,SYS$OUTPUT のリダイレクトは,最後のパイプライン・セグメント・コマンドだけに使用でき,SYS$INPUT のリダイレクトは,最初のパイプライン・セグメント・コマンドだけに使用できます。
PIPE コマンドのリダイレクトは,DEFINE コマンドや ASSIGN コマンドを使用して行うリダイレクトとは 異なります。相違点を以下に示します。
SYS$OUTPUT をリダイレクトすると,コマンド・シーケンスが実際に SYS$OUTPUT に書き込むかどうかにかかわらず,常にリダイレクトされた出力ファイルが作成されます。リダイレクトされた出力ファイルと同じ名前を持つファイルのバージョンがすでに存在する場合,そのファイルの新しいバージョンが作成されます。この動作は,スーパバイザ・モードで DEFINE または ASSIGN コマンドを使用して,SYS$OUTPUT を再定義する場合と同じです。リダイレクトされたファイルは,コマンド・シーケンスが実行される前に作成されることに注意してください。次の例のように,リダイレクトされたファイルがコマンド・シーケンスでも使用される場合は,操作が失敗することがあります。
$ PIPE SEARCH TRANS.LOG "alpha" > TRANS.LOG %SEARCH-W-OPENIN, error opening TRANS.LOG;2 as input -RMS-E-FLK, file currently locked by another user |
この例では,新しいバージョンの TRANS.LOG が作成され,書き込みアクセス用にオープンされます。次に SEARCH コマンドが,前のバージョンではなく最新バージョンの TRANS.LOG に読み込みアクセスしようとします。
SYS$ERROR をリダイレクトすると,コマンド・シーケンスが実行中に実際に SYS$ERROR に書き込む場合のみ,リダイレクトされたファイルが作成されます。リダイレクトされたエラー・ファイルと同じ名前を持つ既存のファイルは存在しません。リダイレクトされたエラー・ファイルと同じ名前を持つファイルがすでに存在する場合は,そのファイルがリダイレクトされたエラー・ファイルとしてオープンされます。次に,このコマンド・シーケンスで作成されたエラー出力は,リダイレクトされたエラー・ファイルの最後に追加されます。この動作は,スーパバイザ・モードで DEFINE または ASSIGN コマンドを使用して,SYS$ERROR を再定義する場合と同じです。
前へ | 次へ | 目次 | 索引 |