IBM主机技术一本通
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6 条件JCL

条件JCL用来设定作业步执行的条件,如果这些条件没有满足,作业就不能够执行。当IF从句里的条件满足时,THEN从句表示开始处理作业步;如果没有满足,就执行ELSE从句中设定的内容。

条件JCL即IF/THEN/ELSE/ENDIF语句的语法格式(语句结构)为:

        //name IF(relational-expression)THEN
        //name当relational-expression成立(为真)时要执行的JCL语句
        //name ELSE
        //name当relational-expression不成立(为假)时要执行的JCL语句
        //name ENDIF

条件JCL即IF/THEN/ELSE/ENDIF语句结构,可以在作业的JOB语句后面的任何地方编写。在上面的结构中,name是定义条件JCL语句的标号(名字),它必须满足JCL中对名字字段的要求,下面是一些合法名字的例子。

        //BANK1 IF (relational-expression) THEN
        //DEPOSIT IF (relational-expression) THEN
        //PGM#1 IF (relational-expression) THEN

下面这些名字则是不合法的,原因列在右边。

        // BANK1         (名字没有从第3列开始)
        //CHECKCODE      (超过8个字符)
        //CHKRC#2IF      (名字后面需要空格,才能写IF语句)

在条件JCL中,我们发现IF、ELSE或ENDIF短语都是写在原来JCL操作符位置的。IF语句总是出现在条件表达式(relational-expression)和标识符THEN的前面。跟在IF语句后面的是所有条件满足时要执行的JCL语句,如果没有要执行的语句,则ELSE语句要紧跟在IF语句的后面。

跟在ELSE语句后面的是当条件表达式不成立时要执行的所有JCL语句。如果没有要执行的语句,就可以省略ELSE语句。ELSE语句没有参数,跟在ELSE操作符后面的字符串,系统都当成注解处理。

ENDIF语句说明IF/THEN/ELSE/ENDIF语句的结束。跟在IF语句或ELSE语句之后至少有一条EXEC语句。ENDIF语句也没有参数,所有跟在ENDIF语句后面的字符串,系统都当成注解处理。

跟在IF语句后面的条件表达式(Relational-Expression)指定判断的条件。条件表达式的值是布尔变量,即不是真就是假。在下面的例子中,IF语句检查的是返回码是否等于4。

        //CHECK IF RC=4 THEN

条件表达式也可以用括号括起来,比如,上面的IF语句也可以改写成下面这样。

        //CHECK IF(RC = 4)THEN

IF语句与条件表达式之间至少要有一个空格,同样地,条件表达式与THEN短语之间也至少需要一个空格。如果条件表达式很长,一行写不完,可以在下一行继续。为了继续条件表达式,可以将表达式在一个合法的空格位置断开并从下一行的第4列到第16列继续,这跟JCL语句的规则是一样的。

        //CHECK IF((RC = 4)|(RC < 8)|
        // ABEND)THEN

条件表达式的比较操作符用来将关键字与一个数值进行比较。比较的结果只能是真或假,比较操作符可以使用算术运算符或字母表示,下面是可用的8种表达方式。

● GT or >大于。

● GE or >=大于或等于。

● NG or ¬>不大于。

● EQ or =等于。

● NE or ¬=不等于。

● LT or <小于。

● LE or <=小于或等于。

● NL or ¬<不小于。

在下面的例子中,IF语句检查是否返回码小于4。在条件表达式的前面和后面都必须至少有一个空格,以将它与IF或THEN短语分隔开来:

        //CHECK IF RC<4 THEN

算术运算符前后的空格不是必需的,但如果比较运算符使用字母,就必须前后至少有一个空格,比如,上面的IF语句可以改写成:

        //CHECK IF RC LT 4 THEN

条件表达式的括号是可选的,但如果有多个表达式用逻辑运算符连接在一起,括号就非常有用了。可以使用的逻辑操作符有:

● AND(&)。

● OR(|)。

● NOT(¬)。

操作符AND(&)的结果值只有在两端的关系表达式都为真时才为真。AND操作符的前后必须至少有一个空格。比如,要检查返回码的值是否在4和8之间,IF语句必须写成:

        //CHECK IF (RC>4 & RC<8) THEN

操作符OR(|)的结果值只要两端的关系表达式有一个为真时就为真。操作符OR的前后必须有至少一个空格。比如,下面的IF语句检查返回码是否为4或8。

        //CHECK IF (RC=4 | RC=8) THEN

操作符NOT(¬)用来将表达式的结果反过来。操作符NOT与关系表达式之间不需要用空格隔开。系统在任何比较和逻辑操作符之前检查NOT操作符,即操作符NOT运算的优先级最高。下面的例子用来检查返回码的值是否不等于8。

        //CHECK IF ¬(RC=8) THEN

关系表达式中的关键字说明你要测试的对象,它们可以是返回码(Return Code)、异常结束状态码(Abend Condition)、异常结束完成码(Abend Completion Code)以及作业步是否执行完等。关系表达式的关键字有:

● RC返回码。

● ABEND异常结束。

● ¬ ABEND没有异常结束。

● ABENDCC异常结束状态码。

● RUN作业步执行过。

● ¬RUN作业步没有执行。

每个关键字的前面可以有一个作业步名字以表明该条件表达式是检查某个特定作业步的。其格式为:

        stepname.keyword

如果作业有调用过程,则在关键字的前面需要同时带有作业步的名字和过程步的名字,以表明要检查的是特定作业步对应的过程步,其格式为:stepname.procstepname.keyword。

关键字返回码(RC)代表前面已执行的作业步的最大返回码。下面的例子检查前面执行的作业步的最大返回码是否小于4。

        //CHECK IF RC<4 THEN

下面的例子则只检查之前的COBOL作业步的返回码是否小于4。

        //CHECK IF(COBOL.RC<4)THEN

再下面的例子由于调用了过程,因此必须检查作业步COBOL调用的过程PGM1后的返回码的值是否小于4。

        //CHECK IF (COBOL.PGM1.RC<4) THEN

关键字ABEND用来检查前面已执行的作业步是否有异常结束(abnormal termination),其语法格式为:

        //name IF ABEND THEN或
        //name IF ABEND = TRUE THEN

说明两条语句都是用来检查前面执行的作业步中有没有异常结束的。像上面的返回码关键字一样,两条语句的前面都可以加上作业步或过程步的名字以指定对特定作业步的检查。下面是两个例子。

        //CHECK IF ABEND THEN
        //CHECK IF COBOL.ABEND = TRUE THEN

关键字¬ABEND用来检查前面执行的作业步是否有异常结束,其语法格式为:

        //name IF ¬ABEND THEN或
        //name IF ABEND = FALSE THEN

两条语句都是用来检查前面执行的作业步确实没有发生异常结束情况的。像上面的返回码关键字一样,两条语句的前面都可以加上作业步或过程步的名字,以指定对特定作业步的检查。下面是两个例子。

        //CHECK IF ¬ABEND THEN
        //CHECK IF COBOL.ABEND = FALSE THEN

条件表达式关键字ABENDCC用来检查特定的系统异常结束码或用户定义的异常完成代码,其格式为:

        ABENDCC = Sxxx,其中,S表示异常结束时的系统完成代码(Abnormal system completion code)。
        ABENDCC = Uxxxx,其中,U表示异常结束时,用户定义的完成代码(Abnormal user-defined completion code)。

像上面的关键字一样,两条语句的前面都可以加上作业步或过程步的名字以指定对特定作业步的检查。下面的例子检查前面的作业步中有没有程序系统完成码0C7,S0C7是程序运行中常见的错误码,表明程序数据出现了问题,导致了数据例外(Data Exception)。

        //CKABEND IF ABENDCC = S0C7 THEN

下面的例子则是检查作业步GOPGM1是否出现了用户定义的异常返回码U0168。

        //CKABEND IF GOPGM1.ABENDCC = U0168 THEN

关键字RUN用来检查特定的作业步是否已经执行过了。作业步或作业步加过程作业步的名字必须出现在关键字RUN的前面。其语法格式为:

        //name IF stepname.RUN THEN或
        //name IF stepname.RUN = TRUE THEN

关键字¬RUN用来检查特定的作业步是否没有执行。作业步或作业步加过程作业步的名字必须出现在关键字¬RUN的前面。其语法格式为:

        //name IF ¬stepname.RUN THEN或
        //name IF stepname.RUN = FALSE THEN

在下面的例子中,关键字¬RUN检查链接(LKED)作业步是否有执行。如果作业步LKED没有执行,就执行程序PGMEXIT:

        000001 //IBMUSERC JOB 168,NEWMAN,CLASS=A,MSGCLASS=H,
        000002 //       NOTIFY=&SYSUID,MSGLEVEL=(1,1)
        000003 //COBOL  EXEC  PGM=IGYCRCTL,REGION=2048K,
        000004 //      PARM='NODYNAM,LIB,OBJECT,RENT,RES,APOST,MAP,XREF,OFFSET'
        000005 //LKED   EXEC PGM=HEWL,COND=(8,LT,COBOL),REGION=1024K,
        000006 //        PARM='LIST,XREF'
        000007 //CKRUN  IF ¬LKED.RUN THEN
        000008 //TEST   EXEC PGM=PGMEXIT

条件JCL语句IF/THEN/ELSE/ENDIF的THEN短语由IF/THEN语句和下面任何一种语句之间的JCL语句组成。

● 对应的ELSE语句(如果指定了的话)。

● 对应的ENDIF。

THEN短语的目的是提供IF测试条件成立时要执行的一组JCL语句。如果没有指定JCL语句,则THEN就变成了空(null)的THEN短语。下面的例子演示THEN短语的用法。

        //CKECKRC   IF (RC>=4) THEN
        //DELFIL   EXEC PGM=IEFBR14
        //         ENDIF
        //DEFFIL   EXEC PGM=IDCAMS

上面例子中的THEN短语包含名为DELFIL的JCL语句,程序IEFBR14在EXEC语句中指定,只有在前面的作业步的返回码大于4 时才会执行。无论返回码的值是多少,指定在作业步DEFFIL中的程序IDCAMS都会执行,因为该作业步不是IF/THEN/ELSE/ENDIF语句结构的一部分。

IF/THEN/ELSE/ENDIF语句中的ELSE短语指的是介于关键字ELSE与对应的ENDIF语句之间的JCL语句。ELSE短语的目的是提供IF语句测试条件不成立时要执行的JCL语句组。如果没有指定JCL语句,ELSE短语就变成空(null)ELSE短语。下面的JCL语句演示了ELSE短语的用法。

        000001 //IBMUSERC JOB 168,NEWMAN,CLASS=A,MSGCLASS=H,
        000002 //       NOTIFY=&SYSUID,MSGLEVEL=(1,1)
        000003 //COBOL  EXEC  PGM=IGYCRCTL,REGION=2048K,
        000004 //      PARM='NODYNAM,LIB,OBJECT,RENT,RES,APOST,MAP,XREF,OFFSET'
        000005 //LKED   EXEC PGM=HEWL,COND=(8,LT,COBOL),REGION=1024K,
        000006 //        PARM='LIST,XREF'
        000007 //CKRUN  IF ¬LKED.RUN THEN
        000008 //TEST   EXEC PGM=PGMEXIT
        000009 //      ELSE
        000010 //GORUN  EXEC PGM=GORUN
        000011 //      ENDIF
        000012 //COMPARE EXEC PGM= IEBCOMPR

在上面的例子中,THEN短语包含作业步TEST,如果LKED作业步没有执行,就会运行该作业步的程序PGMEXIT。如果作业步LKED执行了,就不会执行作业步TEST中的程序PGMEXIT,而会执行第10行的ELSE短语,即执行程序GORUN。

不管作业步LKED是否有执行,作业步COMPARE中的程序IEBCOMPR都会执行,因为它不是条件JCL语句IF/THEN/ELSE/ENDIF结构的一部分。ENDIF短语用来结束IF/THEN/ELSE/ENDIF语句结构,每个IF语句都要有一条对应的ENDIF短语。

下面的作业流是一个银行系统的实际例子,我们将IF、ELSE和ENDIF语句用加粗体标出来了。第11行的IF语句检查作业步IDCAM的最大返回代码(MAXCC),如果不是0,本作业步会将MAXCC置为04。请注意,第11行的IF语句不是我们这里介绍的条件JCL中的IF语句,第8行到第13行的语句都是程序IDCAMS的控制语句,它们连JCL语句都不是,因此,这里的IF语句不需要有ENDIF与其配套。

第15行的IF语句检查作业步IDCAM的返回码是否为4,如果是就执行第17行到第26行的THEN短语,即执行作业步IEBGEN1,否则执行第28行到第39行的ELSE短语,即不会执行IEBGEN1而直接执行IEBGEN2。

        000001 //IBMUSERA JOB (36512),'IBMUSER',CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1),
        000002 // NOTIFY=IBMUSER
        000003 //IDCAM   EXEC PGM=IDCAMS,REGION=512K
        000004 //SYSPRINT DD  SYSOUT=*
        000005 //IN      DD  DSN=IBMUSER.TAPTKWD.V52.JCLLIB(HEAD),DISP=SHR
        000006 //OUT     DD  DSN=NULLFILE,DCB=(RECFM=FB,LRECL=80,BLKSIZE=8000)
        000007 //SYSIN   DD  *
        000008       REPRO IFILE(IN)
        000009       OFILE(OUT)
        000010       COUNT(2)
        000011       IF   MAXCC NE 0 THEN
        000012           SET  MAXCC=04
        000013 /*
        000014 //*********************************************************************
        000015 //CHECK IF NOT(IDCAM.RC = 4) THEN
        000016 //*********************************************************************
        000017 //IEBGEN1  EXEC  PGM=IEBGENER
        000018 //*********************************************************************
        000019 //SYSUT1   DD  DSN=IBMUSER.TAPTKWD.V52.JCLLIB(HEAD),DISP=SHR
        000020 //        DD  DSN=IBMUSER.TAPTKWD.V52.JCLLIB(DETAIL1),DISP=SHR
        000021 //SYSUT2   DD  DSN=IBMUSER.TAPTKWD.D030217,
        000022 //               SPACE=(TRK,(1,1)),
        000023 //               DISP=(NEW,CATLG,UNCATLG),
        000024 //               DCB=(BLKSIZE=8000,LRECL=80)
        000025 //SYSPRINT DD  SYSOUT=*
        000026 //SYSIN   DD  DUMMY
        000027 //CHECK ELSE
        000028 //*********************************************************************
        000029 //IEBGEN2  EXEC  PGM=IEBGENER
        000030 //*********************************************************************
        000031 //SYSUT1   DD  DSN=IBMUSER.TAPTKWD.V52.JCLLIB(HEAD),DISP=SHR
        000032 //        DD  DSN=IBMUSER.TAPTKWD.V52.JCLLIB(DETAIL1),DISP=SHR
        000033 //        DD  DSN=IBMUSER.TAPTKWD.V52.JCLLIB(DETAIL2),DISP=SHR
        000034 //SYSUT2   DD  DSN=IBMUSER.TAPTKWD.D030217,
        000035 //                   SPACE=(TRK,(1,1)),
        000036 //                   DISP=(NEW,CATLG,UNCATLG),
        000037 //                   DCB=(BLKSIZE=8000,LRECL=80)
        000038 //SYSPRINT DD  SYSOUT=*
        000039 //SYSIN   DD  DUMMY
        000040 //CHECK  ENDIF

条件JCL语句可以嵌套,其最大的嵌套层数不能超过15层。一个IF/THEN/ELSE/ENDIF语句可以包含另一个IF/THEN/ELSE/ENDIF语句,以此类推,在IF/THEN/ELSE/ENDIF语句中名字和注解是可选的。如果没有名字,则第3列为空,一个IF/THEN/ELSE/ENDIF语句在作业中可以在JOB语句之后的任何位置上使用。

在嵌套的条件结构中,THEN短语或ELSE会包含额外的IF/THEN/ELSE/ENDIF结构。每个额外的结构都有自己对应的IF/THEN、ELSE和ENDIF语句。

在下面的例子中,作业流检查程序的返回码用于决定要执行的下一个步骤。

        //COBOL   EXEC PGM=IGYCRCTL
        //CHKCOB  IF (COBOL.RC<=4) THEN
        //LKED   EXEC PGM=HEWL
        //CHKLKED IF (LKED.RC>4) THEN
        //DELFIL  EXEC PGM=IEFBR14
        //       ELSE
        //RUNPGM  EXEC PGM=PGM1
        //       ENDIF
        //       ENDIF
        //COMPARE EXEC PGM= IEBCOMPR

在外面的IF/THEN/ELSE/ENDIF结构中,CHKCOB语句检查编译(COBOL)作业步的返回码是否小于或等于4。如果条件满足,就执行作业步链接(LKED)。

接下来调用下一层的IF/THEN/ELSE/ENDIF结构,如果连接(LKED)作业步的返回码大于4,就会执行作业步DELFIL中的程序IEFBR14。如果LKED作业步的返回码小于或等于4,就会执行作业步RUNPGM。最后的作业步COMPARE不管前面的测试条件如何,总会执行,因为它不是条件JCL中的一部分。