# OpenVMS
ユーザーズ・マニュアル

前へ | 次へ | 目次 | 索引

## 16.14.3 ファイルへのレコードの追加

OPEN/APPEND コマンドは，既存のファイルの終端にレコードを追加します。レコードをファイルに追加するには，次のようにします。

手順 | 操作
--- | ---
1 | OPEN コマンドと一緒に /APPEND 修飾子を使用して，レコード・ポインタをファイルの終端に置く。 /APPEND 修飾子は，ファイルの新しいバージョンは作成しない。
2 | WRITE コマンドを使用して新しいデータ・レコードを書き込む。
3 | すべてのレコードが終了するまで，レコードを追加し続ける。
4 | CLOSE コマンドを使用してファイルをクローズする。

以下のコマンド・プロシージャは STATS.DAT という名前のファイルの末尾にレコードを追加しています。

    $! Open STATS.DAT to append files and assign
    $! it the logical name FILE
    $!
    $ OPEN/APPEND FILE DISK4:[MURPHY]STATS.DAT
    $!
    $ BEGIN_LOOP:
    $! Obtain record to be appended and place this
    $! record in the symbol RECORD
    $!
    $     PROMPT:
    $          INQUIRE RECORD -
               "Enter new record (press RET to quit) "
    $          IF RECORD .EQS. "" THEN GOTO END_LOOP
    $! Write record to FILE
    $!
    $          WRITE FILE RECORD
    $          GOTO BEGIN_LOOP
    $!
    $! Close FILE and exit
    $!
    $     END_LOOP:
    $          CLOSE FILE
    $          EXIT

# 16.15 ファイル入出力エラーの処理方法

OPEN，READ，WRITE コマンドのうちのいずれかと一緒に /ERROR 修飾子を使用すると，システム・エラー・メッセージを表示せずに指定されたラベルに制御を渡すことができます。入出力操作中にエラーが生じた場合には， /ERROR 修飾子は他のすべてのエラー制御方式 (READ コマンドの/EDN_OF_FILE 修飾子を除く) に優先します。

次の例は，OPEN コマンドと一緒に /ERROR 修飾子を使用しています。

    $ OPEN/READ/ERROR=CHECK FILE CONTINGEN.DOC
       .
       .
       .
    $ CHECK:
    $  WRITE SYS$OUTPUT "Error opening file"

OPEN コマンドは，読み込みモードで CONTINGEN.DOC ファイルをオープンするように要求しています。ファイルをオープンできない場合 (たとえば，ファイルが存在しない場合) には， OPEN コマンドはエラー状態を戻して，CHECK ラベルに制御を渡します。

/ERROR 修飾子によって指定されたエラー・パスは，コマンド・レベルに設定されている現在の ON 状態に優先します。エラーが生じて，ターゲット・ラベルに制御が渡されると，システムに予約されているグローバル・シンボル $STATUS にエラー・コードが保持されます。エラー処理ルーチンで F$MESSAGE レキシカル関数を使用すれば， $STATUS のメッセージを表示できます。

以下の例では，F$STATUS レキシカルの内容を表示するためにレキシカル関数 F$MESSAGE が使用されています。

    $ OPEN/READ/ERROR=CHECK FILE 'P1'
       .
       .
       .
    $ CHECK:
    $  ERR_MESSAGE = F$MESSAGE($STATUS)
    $  WRITE SYS$OUTPUT "Error opening file: ",P1
    $  WRITE SYS$OUTPUT ERR_MESSAGE
       .
       .
       .

## 16.15.1 省略時のエラー・アクション

OPEN，READ，WRITE，または CLOSE コマンドを使用しているときにエラーが生じ，エラー・アクションを指定しないと，現在のON コマンド・アクションが有効になります。

READ コマンドがファイルの終端メッセージを受け取った場合のエラー・アクションは，次のようにして決定されます。

- /END_OF_FILE 修飾子を使用している場合は，指定されたラベルに制御が渡される。

- /END_OF_FILE 修飾子を使用していない場合は， /ERROR 修飾子に指定されたラベルに制御が渡される。

- どちらの修飾子 (/END_OF_FILE または /ERROR) も指定していない場合には，現在の ON コマンド・アクションが有効になる。

# 16.16 実行フローの制御方法

コマンド・プロシージャでの通常の実行フローは順次です。つまり，ファイルの最後に到達するまで，プロシージャ内のコマンドが順に実行されます。しかし，特定の文を実行するかどうかなど，プロシージャの実行を続行するときの条件を制御することもできます。

この後の節では，次のことについて説明します。

- 実行フローを制御または変更するために使用できる DCL コマンド

  - IF，THEN，ELSE

  - GOTO

  - GOSUB

  - CALL

- コマンド・ブロックの使用

- 場合分けの文の作成

- ループの作成

## 16.16.1 IF コマンドの使用

IF コマンドは，式の値をテストして，式の結果が真の場合にコマンドまたはコマンドのブロックを実行します。式の結果が偽の場合には，次のいずれかになります。

- THEN コマンドの後に 1 つのコマンドが続く場合には， THEN コマンドは実行されず，その後のコマンドが実行される。

- THEN コマンドの後にコマンドのブロックが続き， ELSE コマンドが指定されていない場合には， ENDIF コマンドのすぐ後にコマンドが実行される。

- ELSE コマンドが指定されている場合には，ELSE コマンドの後のコマンドまたはコマンドのブロックが実行される。

DCL の IF コマンドには，2 つの形式があります。 1 つは， 第 15 章 で説明されているように IF コマンドに指定された式が真の場合に単独のコマンドを実行する形式です。

DCL にはブロック構造の IF 形式もあります。ブロック構造のIF コマンドは，指定された式が真の場合に複数のコマンドを実行します。 ELSE 文を指定すれば，式が偽の場合に 1 つ以上のコマンドを実行することができます。

## 16.16.2 THEN コマンドの使用

式が真の場合に複数のコマンドを実行するには，動詞 (前にドル記号が付いた DCL コマンド) として THEN 文を指定し，残りのブロック構造文の終わりに ENDIF 文を指定します。

次の例では，THEN 文は動詞として使用されています。

    $ IF expression
    $   THEN
    $       command
    $       command
       .
       .
       .
    $ ENDIF

## 16.16.3 ELSE コマンドの使用

式が偽の場合に 1 つ以上のコマンドを実行するには，動詞として ELSE 文を指定し，残りのブロック構造文の終わりに ENDIF 文を指定します。

次の例では，ELSE コマンドは動詞として使用されています。

    $ IF expression
    $   THEN
    $       command
    $       command
       .
       .
       .
    $   ELSE
    $       command
    $       command
       .
       .
       .
    $ ENDIF

## 16.16.4 コマンド・ブロックの使用

同じコマンド・プロシージャでコマンドを実行するのか，別のコマンド・プロシージャにコマンドを置いて実行するのかに応じて，コマンド・ブロックにはいくつかの実行方法があります。ガイドラインは次に示します。

- 同じコマンド・プロシージャでコマンドを実行する場合には， THEN 文の後にコマンドを指定する。次の例を参照。

      $ IF condition
      $ THEN  command
              command
         .
         .
         .
      $ ENDIF

- 別のプロシージャでコマンドを実行する場合には， THEN 文の一部としてそのコマンド・プロシージャを呼び出す。次の例を参照。

      $ IF condition
      $ THEN @command_procedure
      $ ELSE command
      $      command
      $ ENDIF

- 非ブロック構造の IF 形式を指定して，指定された条件が満たされれば，ラベルが付いたリージョンに制御を渡すことができる。次の例を参照。

      $ IF not condition THEN GOTO END_LABEL
         .
         .
         .
      $END_LABEL:

IF 式の結果が真の場合には， THEN コマンドの後のコマンド・ブロックを実行できます。コマンド・ブロックを使用する場合には， IF コマンドの後の行に最初のコマンドとして THEN コマンドを指定します。

次の例では，2 つの SET TERMINAL コマンドが実行され， F$MODE が "INTERACTIVE" に等しい場合には，プロシージャは制御をラベル PROCEED に渡します。 F$MODE が "INTERACTIVE" に等しくない場合には，プロシージャは終了します。

    $ IF F$MODE () .EQS. "INTERACTIVE"
    $ THEN
    $    SET TERMINAL/DEVICE=VT200
    $    SET TERMINAL/WIDTH=132
    $    GOTO PROCEED
    $ ENDIF
    $ EXIT
    $PROCEED:

次の例では，IF コマンドと ELSE コマンド，およびコマンド・ブロックを組み合わせて使用する方法を示しています。

    $ INQUIRE DEV "Device to check"
    $ IF F$GETDVI(DEV, "EXISTS")
    $ THEN
    $    WRITE SYS$OUTPUT "The device exists."
    $    SHOW DEVICE 'DEV'
    $    SET DEVICE/ERROR_LOGGING 'DEV'
    $ ELSE
    $    WRITE SYS$OUTPUT "The device does not exist."
    $    WRITE SYS$OUTPUT "Error logging has not been enabled."
    $ ENDIF
    $ EXIT

条件が真の場合には，プロシージャはメッセージを SYS$OUTPUT に書き込み， SHOW DEVICE コマンドと SET DEVICE コマンドを実行します。条件が真でない場合には，プロシージャは 2 つのメッセージを SYS$OUTPUT に書き込みます。

IF-THEN-ELSE を使用する場合には，次のような制限事項があります。

- ネストされた IF 文は 15 レベル以下にする。

- THEN 文で始まるコマンド・ブロックは ELSE または ENDIF 文によって終了する。

- ELSE 文で始まるコマンド・ブロックは ENDIF 文で終了する。

- THEN 文は，IF 文に続く最初の実行可能文として指定する。

- THEN または ELSE 文を含む行にはラベルを指定しない。ただし，ENDIF 文を含む行にはラベルを指定できる。現在のコマンド・ブロックの中ではプログラムを分岐できるが，別のコマンド・ブロックの途中に分岐しないこと。

真の文

IF コマンドに続く文は，1 つ以上の数値定数，文字列リテラル，シンボリック名，レキシカル関数で構成し，論理演算子，算術演算子，または文字列演算子によって区切ります。次のいずれかの値を持つ場合に式は真となります。

- 奇数の整数値

- Y，y，T，t のいずれかの英字で始まる文字列値

- 奇数の整数になる数字を含む文字列値 (たとえば，文字列 "27")

偽の文

次のいずれかの値を持つ場合に式は偽となります。

- 偶数の整数値

- Y，y，T，t 以外の英字で始まる文字列値

- 偶数の整数になる数字を含む文字列値 (たとえば，文字列 "28")

式の作成

IF コマンドの式を作成する場合には，特に，次の点に注意してください。

- IF 文の中でシンボルを使用すると，その値は自動的に置換される。反復置換を強制する必要がある場合を除いて，置換演算子として一重引用符 (') を使用しない。

- 文字列比較演算子の終わりには "S" が付く。たとえば，文字列を比較するには，.EQS.，.LTS.，.GTS. などの演算子を使用する。また，整数を比較するには，.EQ.，.LT.，.GT. の演算子を使用する。

- 2 つの文字列が等しいかどうかを調べる場合は，両方の文字列で同じように大文字と小文字を区別しなければならない。すなわち，文字列 "COPY" は文字列 "copy" または "CoPy" とは等しくない。

この後に示す例は，IF コマンドと一緒に使用できる式を示しています。さらに詳しい例が必要であれば，『Compaq OpenVMS DCL ディクショナリ』のIF コマンドの説明を参照してください。

次の例では，論理演算子を使用し， THEN 文の後の 1 つのコマンドだけを実行します。シンボル CONT が真でない場合には，プロシージャは終了します。

    $ INQUIRE CONT "Do you want to continue [Y/N]"
    $ IF .NOT. CONT THEN EXIT
       .
       .
       .

次の例は，IF 式の中でシンボルとラベルを使用しています。

    $ INQUIRE CHANGE "Do you want to change the record [Y/N]"
    $ IF CHANGE THEN GOTO GET_CHANGE
       .
       .
       .
    $ GET_CHANGE:
       .
       .
       .

CHANGE シンボルが真の場合は，プロシージャはGET_CHANGE ラベルに制御を渡します。それ以外の場合には，IF コマンドの後のコマンドを実行します。

次の例は，2 つの異なる IF コマンドを示しています。

    $ COUNT = 0
    $ LOOP:
    $    COUNT = COUNT + 1
    $    IF COUNT .EQ. 9 THEN EXIT
    $    IF P'COUNT' .EQS. "" THEN EXIT
       .
       .
       .
    $ GOTO LOOP

最初のIF コマンドは 2 つの整数を比較し， 2 番目の IF コマンドは 2 つの文字列を比較しています。整数比較には .EQ. 演算子が，文字列比較には.EQS. 演算子が使用されています。

最初に，COUNT の値が整数の 9 と比較されます。値が等しいとプロシージャは終了し，値が等しくないとプロシージャは継続されます。 8 つのパラメータ (許容最大数) を処理した後，ループが終了します。

2 番目の IF コマンドでは，P'COUNT' シンボルの文字列値を空の文字列と比較して，シンボルが未定義かどうかを調べます。 COUNT シンボルの反復置換を強制するには，一重引用符を使用しなければなりません。たとえば，COUNT が 2 の場合は，最初の変換結果は P2 になります。次に，P2 の値を文字列比較に使用します。

IF 式の結果が真の時に別のコマンド・プロシージャを実行することもできます。次の例では，IF 式の結果が真のときに，コマンド・プロシージャ EXIT_ROUTINE.COM を実行します。

    $ GET_COMMAND_LOOP:
    $    INQUIRE COMMAND -
         "Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE)"
    $    IF COMMAND .EQS. "EXIT" THEN @EXIT_ROUTINE

## 16.16.5 GOTO コマンドの使用

GOTO コマンドは，コマンド・プロシージャ内のラベルの付いた行に制御を渡します (ラベルの使い方についての詳細は， 第 15 章 を参照してください)。 GOTO コマンドは，THEN 句で使用すると特に便利であり，プロシージャを前後に分岐させることができます。たとえば，コマンド・プロシージャでパラメータを使用する場合には，プロシージャの先頭でパラメータをテストし，適切なラベルに分岐できます。

GOTO コマンドまたは GOSUB コマンドの分岐先ラベルは，独立した IF-THEN-ELSE 構造または独立したサブルーチンの内部に存在できません。

次の例では，IF コマンドは，P1 が空文字列でないことをチェックします。

    $ IF P1 .NES. "" THEN GOTO OKAY
    $ INQUIRE P1 "Enter file spec"
    $ OKAY:
    $ PRINT/COPIES=10 'P1'
       .
       .
       .

P1 が空文字列の場合には，GOTO コマンドは実行されず， INQUIRE コマンドはパラメータ値を要求するプロンプトを表示します。それ以外の場合には，GOTO コマンドは INQUIRE コマンドの後に分岐します。どちらの場合も，プロシージャは，OKAY というラベルの付いた行の後の PRINT コマンドを実行します。

次の例では，GOTO コマンドはエラー・メッセージを戻します。これは，分岐先 (TEST_1) が IF-THEN 構造の内部に存在するからです。

    $ GOTO TEST_1
    $ EXIT
    $ IF 1.EQ.1
    $       THEN WRITE SYS$OUTPUT "What are we doing here?"
    $ TEST_1:
    $       WRITE SYS$OUTPUT "Got to the label"
    $ ENDIF
    $ EXIT

### 16.16.5.1 再実行の回避

正常に実行されたジョブの一部が再実行されないようにするときにも GOTO コマンドを使用できます。この場合は，次のようにします。

手順 | 操作
--- | ---
1 | プロシージャの中の開始ポイントにラベルを付ける。
2 | ラベルの後，SET RESTART_VALUE = ラベル名 コマンドを使用して，再開ポイントをそのラベルに設定する。 SET RESTART_VALUE = ラベル名 コマンドの実行後にバッチ・ジョブが中断された場合，システムはバッチ・ジョブを再開するときにグローバル・シンボル BATCH$RESTART に該当するラベル名を割り当てる。
3 | プロシージャの先頭で，$RESTART シンボルの値をテストする。 $RESTART が真の場合には，BATCH$RESTART シンボルを転送ラベルとして使用して GOTO 文を実行する。

$RESTART グローバル・シンボル

$RESTART は，システムがユーザ用に残してある予備グローバル・シンボルです。いずれか 1 つのバッチ・ジョブが中断後に再開された場合は，$RESTART は真であり，そうでない場合は，$RESTART は偽です。予備グローバル・シンボル $RESTART は削除できません。

コマンド・プロシージャの中に SET RESTART_VALUE コマンドがあり，この要素の中でジョブを再実行したい場合には， SET ENTRY/NOCHECKPOINT コマンドを入力して，グローバル・シンボル BATCH$RESTART を削除します。中断されたジョブを再起動した場合には，ジョブは中断されたセクション内で実行されます。

次のコマンド・プロシージャは，バッチ・ジョブの中で値を再開する方法を示しています。

    $ ! Set default to the directory containing
    $ ! the file to be updated and sorted
    $ SET DEFAULT DISK1:[ACCOUNTS.DATA84]
    $
    $ ! Check for restarting
    $ IF $RESTART THEN GOTO 'BATCH$RESTART'
    $
    $ UPDATE_FILE:
    $ SET RESTART_VALUE = UPDATE_FILE
       .
       .
       .
    $ SORT_FILE:
    $ SET RESTART_VALUE = SORT_FILE
       .
       .
       .
    EXIT

このコマンド・プロシージャを再開可能なバッチ・ジョブとしてキューに登録するには，ジョブを登録するときに SUBMIT コマンドと一緒に/RESTART 修飾子を指定します。割り込まれたジョブを再開する場合は，割り込みのあった場所からジョブの実行が開始されます。たとえば，SORT_FILE ルーチンの中でジョブに割り込みがあった場合は，ジョブを再開すると，SORT_FILE ラベルから実行が開始されます。

システムで障害が発生した場合には，プロセス環境の大部分は維持管理されません。システム障害が発生した後も管理されるシンボルは， $RESTART と BATCH$RESTART だけです。したがって，コマンド・プロシージャで使用したシンボルやプロセス論理名は，それぞれの SET RESTART_VALUE コマンドの後で再定義するか，または $RESTART が真のときに実行される THEN ブロックの内部で再定義しなければなりません。シンボルと論理名を THEN ブロックの内部で定義した場合には，コマンド GOTO 'BATCH$RESTART' を THEN ブロックの最後のコマンドとして指定しなければなりません。

前へ | 次へ | 目次 | 索引