[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

OpenVMS 用户手册


前页 目录 索引

13.5.3 第 3 步: 添加循环

循环是重复执行直到满足条件的一组语句。循环操作如下所示:

  1. 从用户输入获得值 
  2. 处理命令
  3. 重复处理,直到用户退出命令过程

要编写循环,遵循这个过程:

步骤 动作
1 从标号开始循环。
2 测试变量,确定是否需要执行循环中的命令。
3 如果不需要执行循环,则前去循环的末端。
4 如果需要执行循环,则执行在循环体中的命令,然后返回到循环的开始。
5 结束循环。

以下例子展示 CLEANUP.COM 命令过程中的循环使用:


$ GET_COM_LOOP:
$     INQUIRE COMMAND-
$     "Enter command (DELETE, DIRECTORY. EXIT, PRINT, PURGE, TYPE)"
$     IF COMMAND .EQS. "EXIT" THEN GOTO END_LOOP
$!
$! Execute if user entered DELETE
$ DELETE:
$     IF COMMAND .NES. "DELETE" THEN GOTO DIRECTORY
$     WRITE SYS$OUTPUT "This is the DELETE section."
$     GOTO GET_COM_LOOP
   .
   .
   .
$ END_LOOP:
$     WRITE SYS$OUTPUT "Directory ''F$DIRECTORY()' has been cleaned"
$ EXIT

一旦命令执行,控制就传递回 GET_COM_LOOP 标号,直到用户输入 EXIT 命令。当输入 EXIT 命令时,这个过程输出一条消息声明目录已被清理。

13.5.4 第 4 步: 结束命令过程

要结束命令过程,遵循这个过程:

步骤 动作
1 决定在哪里需要退出或放弃命令过程。
2 放置 EXIT 或 STOP 命令。

13.5.4.1 使用 EXIT 命令

可以把 EXIT 命令放在命令过程中:

  • 确保过程不执行某些行
  • 结束有一个以上执行路径的过程
  • 结束命令过程

以下是一个使用 EXIT 命令的例子,可避免执行位于过程末端的出错处理例行程序:


   .
   .
   .
$ EXIT ! End of normal execution path
$ ERROR_ROUTINE
   .
   .
   .

以下是一个使用 EXIT 命令的例子,可结束有一个以上执行路径的过程:


$ START:
$     IF P1 .EQS. "TAPE" .OR. P1 .EQS. "DISK" THEN GOTO 'P1'
$     INQUIRE P1 "Enter device (TAPE or DISK)"
$     GOTO START
$ TAPE: !Process tape files
   .
   .
   .
$     EXIT
$ DISK: ! Process disk files
   .
   .
   .
$     EXIT

在每个标号 (TAPE 和 DISK) 后面的命令为过程提供不同路径。在 DISK 标号之前的 EXIT 命令确保不执行在 DISK 标号之后的命令,除非明确到达这个标号的过程分支。

在过程的末端不需要 EXIT 命令,因为过程的文件结束标记(end-of-file) 引起一个潜在的 EXIT 命令。然而,Compaq 建议您使用 EXIT 命令。

13.5.4.2 使用 STOP 命令

在命令过程中,可以使用 STOP 命令确保如果发生严重出错则终止过程。如果 STOP 命令出现在交互执行的命令过程中,那么控制将返回到 DCL 级。如果命令过程以批量模式执行,则批量作业终止。

这个命令行告诉过程如果发生严重出错就停止:


$ ON SEVERE_ERROR THEN STOP

13.5.5 第 5 步: 测试和调试程序逻辑

一旦使用程序桩编写代码,就应该测试命令过程的全部逻辑。应该测试所有可能的执行路径。

遵循这个过程测试和调试命令过程:

步骤 动作
1 在命令过程中输入每个有效命令以测试程序逻辑。
2 输入无效命令以继续测试程序逻辑。
3 使用 EXIT 命令退出命令过程以完成测试程序逻辑。
4 如果必要,就使用 SET VERIFY、SET PREFIX 或 SHOW SYMBOL 命令来调试程序。

以下例子展示如何通过输入和执行每个可能命令、无效命令然后退出测试命令过程:


$ @CLEANUP
  Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE): DELETE
  This is the DELETE section.
  Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE): DIRECTORY
  This is the DIRECTORY section.
   .
   .
   .
  Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE): PRINF
  You have entered an invalid command.
  Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE): EXIT
$

13.5.5.1 调试命令过程

可以使用以下命令帮助调试命令过程:

  • SET VERIFY
    显示每行然后执行之。校验出错时,可查看这个错误和发生这个错误所在的行。可以使用 SET VERIFY 命令的关键字指出只校验某些命令行或数据行。
    SET VERIFY 命令保持有效,直到您注销、输入 SET NOVERIFY 命令或者使用 F$VERIFY 词法函数更改校验设置。(第 15 章包含更改校验设置的详情。)
  • SET PREFIX
    如果校验生效,也可以使用 DCL 命令 SET PREFIX 对过程日志文件标记时间戳,方法是在每个命令行前加上它的执行时间。
  • SHOW SYMBOL
    SHOW SYMBOL 命令可以用来确定符号是如何在过程中定义的。

例子: 使用 SET VERIFY 命令进行调试

在以下例子中,标号 END_LOP 拼写错误。因为启用校验,故可以精确地查看在哪里出错:


$ SET VERIFY
$ @CLEAN
$ GET_COM_LOOP:
$    INQUIRE COMMAND -
     "Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE)"
 Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE): EXIT
$    IF COMMAND .EQS. "EXIT" THEN GOTO END_LOP
%DCL-W-USGOTO, target of GOTO not found -
 check spelling and presence of label

要纠正这个错误,可把标号更改为 END_LOOP。

例子: 使用 SET PREFIX 命令进行调试

以下例子说明时间戳的使用:


$  SET VERIFY
$  @TEST
$  SET DEFAULT SYS$LOGIN
$  SHOW DEFAULT
   USER$:[SMYTHE]
$  SET PREFIX "(!5%T) "
$  @TEST
 (17:52)  $ SET DEFAULT SYS$LOGIN
 (17:52)  $ SHOW DEFAULT
   USER$:[SMYTHE]

例子: 使用 SHOW SYMBOL 命令进行调试

以下例子展示 SHOW SYMBOL 命令是如何用来确定符号 COMMAND 是怎样定义的:


$ SET VERIFY
$ @CLEAN
$ GET_COM_LOOP:
$    INQUIRE COMMAND -
     "ENTER COMMAND (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE)"
  ENTER COMMAND (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE): EXIT
$ SHOW SYMBOL COMMAND
 COMMAND = "EXIT"
$    IF COMMAND .EQS. "exit" THEN GOTO END_LOOP
   .
   .
   .

SHOW SYMBOL 命令展现符号 COMMAND 的值为 "EXIT"。因为 INQUIRE 命令自动把输入转换为大写字母而测试命令的 IF 语句使用小写字母字符串 "exit",因此 DCL 确定这些字符串是不同的。要纠正这个错误,确定在 IF 语句中的引用字符串是以大写字母形式写入。这个字符串的其余部分可以使用大写字母,也可以使用小写字母。

13.5.5.2 允许校验执行

当命令过程执行允许校验时,也可以中断它。当命令过程不包含 SET VERIFY 命令或 Ctrl/Y 组合键时,通过以下这些步骤可以允许校验:

步骤 动作
1 按下 Ctrl/Y 可中断执行。
2 输入 SET VERIFY 命令。
3 输入 CONTINUE 命令可继续执行命令过程 (允许校验)。

13.5.6 第 6 步: 添加清除任务

一般而言,命令过程的执行不要更改用户的进程状态。因此,命令过程应该包括一组把进程返回到它的原始状态的命令。这组命令通常是标号为 "CLEAN_UP" 的子例行程序部分。普通的清除操作包括关闭文件和重新设置默认设备和目录。

遵循这个过程可把清除任务添加到命令过程:

步骤 任务
1 从一个标号开始清除子例行程序,例如 CLEAN_UP。
2 使用 F$GETJPI 词法函数测试任何打开的文件。
3 使用 DELETE 或 PURGE 命令删除任何临时或无关的文件。
4 如果更改了任何默认 (例如设备或目录),则使用 SET DEFAULT 命令把它们恢复到它们的原始状态。
5 包括 ON CONTROL_Y 语句确保清除操作能执行。

13.5.6.1 关闭文件

如果打开了任何文件,在退出过程之前确保关闭它们。可以使用词法函数 F$GETJPI 检查保持进程的打开文件定额 (FILCNT)。如果 FILCNT 在命令过程的开始和结束是一样的,那么就知道已关闭所有文件。

这些命令是用于警告用户还有打开的文件:


$ FIL_COUNT = F$GETJPI ("","FILCNT")
   .
   .
   .
$ IF FILCNT .NE. F$GETJPI ("", "FILCNT") THEN-
  WRITE SYS$OUTPUT "WARNING -- file left open)

13.5.6.2 删除临时或无关文件

如果建立了临时文件,就删除它们。一般而言,如果更新了任何文件,就应该清除它们以删除以前的副本。在删除您尚未建立的文件之前,确定您要删除它们。例如,如果您更新了一个包含重要数据的文件,就可以可选地进行清除操作。

如果您更改了默认设备、目录,那么在退出命令过程之前重新设置原始默认。要保存原始的默认目录名,使用 F$ENVIRONMENT 词法函数的 DEFAULT 关键字。在命令过程的末端,包括一个 SET DEFAULT 命令恢复保存的设备和目录。

这个例子的命令行展示保存和恢复设备和目录的默认值:


$ SAV_DEFAULT = F$ENVIRONMENT ("DEFAULT")
   .
   .
   .
$ SET DEFAULT 'SAV_DEFAULT'

13.5.6.3 通常更改的进程特征

下表列出其他通常更改的进程特征,词法函数用来保存进程特征,而词法函数或命令用来恢复进程特征:

特征 用于保存的词法函数 用于恢复的词法函数
DCL 提示 F$ENVIRONMENT SET PROMPT
默认保护 F$ENVIRONMENT SET PROTECTION/DEFAULT
特权 F$SETPRV F$SETPRV 或 SET PROCESS/PRIVILEGES
控制字符 F$ENVIRONMENT SET CONTROL
校验 F$VERIFY F$VERIFY
消息格式 F$ENVIRONMENT SET MESSAGE
键状态 F$ENVIRONMENT SET KEY

有关这些词法函数的完整描述,请参阅 OpenVMS DCL Dictionary

13.5.6.4 确保执行清除操作

要确保即使命令过程异常结束也要执行清除操作,在命令过程中使用以下语句开始每个命令级:


$ ON CONTROL_Y THEN GOTO CLEANUP

有关使用 ON CONTROL_Y 命令的详情,请参阅第 14 章

13.5.7 第 7 步: 完成命令过程

当正确完成一般设计时,做以下几步完成命令过程:

步骤 任务
1 在命令过程中替换第一个程序桩的命令。
2 测试命令过程,确保新命令恰当地操作。
3 如果有必要调试命令过程。
4 第一个程序桩完成时,转向下一个,以此类推,直到替换所有程序桩。

例子: 用命令替换程序桩

以下例子展示 CLEANUP.COM 的 TYPE 段的代码:


$! Execute if user entered TYPE
$! TYPE:
$      IF COMMAND .NES. "TYPE THEN GOTO ERROR
$      INQUIRE FILE "File to type"
$      TYPE 'FILE'
$      GOTO GET_COM_LOOP 
 

这将替换现有代码:


$ WRITE SYS$OUTPUT "This is the TYPE section."

例子: CLEANUP.COM 命令过程

以下是已完成的 CLEANUP.COM 命令过程的例子:


$ GET_COM_LOOP:
$    INQUIRE COMMAND -
     "Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE)"
$    IF COMMAND .EQS. "EXIT" THEN GOTO END_LOOP
$!
$!Execute if user entered DELETE
$ DELETE:
$       IF COMMAND .NES. "DELETE" THEN GOTO DIRECTORY
$       INQUIRE FILE "File to delete? "
$       DELETE 'FILE'
$       GOTO GET_COM_LOOP
$!
$!Execute if user entered DIRECTORY
$ DIRECTORY:
$       IF COMMAND .NES. "DIRECTORY" THEN GOTO PRINT
$       DIRECTORY
$       GOTO GET_COM_LOOP
$!
$!Execute if user entered PRINT
$ PRINT:
$       IF COMMAND .NES. "PRINT" THEN GOTO PURGE
$       INQUIRE FILE "File to print? "
$       PRINT SYS$OUTPUT 'FILE'
$       GOTO GET_COM_LOOP
$!
$!Execute if user entered PURGE
$ PURGE:
$       IF COMMAND .NES. "PURGE" THEN GOTO TYPE
$       PURGE
$       GOTO GET_COM_LOOP
$!
$!Execute if user entered TYPE
$ TYPE:
$       IF COMMAND .NES. "TYPE" THEN GOTO ERROR
$       INQUIRE FILE "File to type"
$       TYPE 'FILE'
$       GOTO GET_COM_LOOP
$!
$ ERROR:
$       WRITE SYS$OUTPUT "You entered an invalid command."
$       GOTO GET_COM_LOOP
$!
$ END_LOOP:
$ WRITE SYS$OUTPUT "Directory ''F$DIRECTORY()' has been cleaned."
$
$ EXIT

13.6 执行命令过程

要使命令过程运行,必须执行它。您可以执行命令过程:

  • 从另一个命令过程中
  • 在远程节点上
  • 作为参数或限定词给 DCL 命令
  • 交互地
  • 作为批量作业
  • 在磁盘和磁带卷上

以下几节描述每一种方法。

13.6.1 在其他命令过程中执行命令过程

通过包括执行过程 (@) 命令,可以从一个命令过程内执行另一个命令过程。

以下命令过程 WRITEDATE.COM 调用命令过程 GETDATE.COM:


$! WRITEDATE.COM
$!
$ INQUIRE TIME "What is the current time in hh:mm format?"
$ @GETDATE [JONES.COM]GETDATE.COM

13.6.2 执行远程节点上的命令过程

您可以使用 TYPE 命令执行在远程节点上另一个帐户顶级目录的命令过程。可以执行命令过程:

  • 显示不提供簇范围服务的本地 OpenVMS 簇系统的服务状态
  • 列出注册到远程节点的用户

输入 TYPE 命令和后面的存取控制字符串。使用以下格式:


$ TYPE nodename"username password"::"TASK=command_procedure"

变量 username 和 password 是远程节点帐户的用户名和密码。

这个命令过程显示注册到该命令过程所驻留的远程节点的用户:


$!SHOWUSERS.COM
$!
$ IF F$MODE() .EQS. "NETWORK" THEN DEFINE/USER SYS$OUTPUT SYS$NET
$ SHOW USERS

在以下例子中,SHOWUSERS.COM 位于节点 ORIOLE 上的 BIRD 帐户的顶级目录中,而密码是 BOULDER。SHOWUSERS.COM 在远程节点 ORIOLE 执行 DCL 命令 SHOW USERS。TYPE 命令显示来自本地节点上 (即是在您输入 type 命令的终端)SHOWUSERS.COM 的输出:


$ TYPE ORIOLE"BIRD BOULDER"::"TASK=SHOWUSERS"

     在 11-DEC-1999 17:20:13.30 时的 OpenVMS 用户进程
               用户总数 = 4,进程数 = 4

 用户名       节点                 交互     子进程       批量
 FLICKER      AUTOMA                2         1
 ROBIN        FABLES                1         2        1
 DOVE         MURMUR                1
 DUCK         FABLES                1         1

13.6.2.1 安全注意事项

使用带存取控制字符串的 TYPE 命令时,您的密码将显现在终端上。要采取适当的安全预防措施,如第 18 章所述。

13.6.3 执行带 DCL 限定词或参数的命令过程

您可以建立一个指定 DCL 命令参数或限定词的命令过程。当有一组参数或限定词频繁使用于一个或多个命令时,这类命令过程是有用的。

在将要经常指定限定词或参数的命令行中输入执行过程命令 (@)。

这个命令过程可以用来为 LINK 命令输入一组限定词:


$! This command procedure contains command
$! qualifiers for the LINK command.
$!
/DEBUG/SYMBOL_TABLE/MAP/FULL/CROSS_REFERENCE

使用 DEFLINK.COM 指定的限定词,这个命令行链接一个对象 SYNAPSE.OBJ:


$ LINK SYNAPSE@DEFLINK

这个命令过程可以用来为 DCL 命令输入参数 CHAP1.TXT、CHAP2.TXT 和 CHAP3.TXT:


$! PARAM.COM
$! This command procedure contains a list of
$! parameters that can be used with commands.
$!
CHAP1, CHAP2, CHAP3

这个命令行指定命令过程 PARAM 代替一列参数。在以下例子中,参数是在 PARAM.COM 中列出的文件名:


$ DIRECTORY/SIZE @PARAM

注意

使用执行过程命令 (@) 时,DCL 把整个指定文件视为命令输入。


前页 后页 目录 索引