Jcl 简明教程

JCL - Quick Guide

JCL - Overview

When to use JCL

JCL 用于大型机环境中,作为程序(例如:COBOL、汇编程序或 PL/I)和操作系统之间的通信。在大型机环境中,可以通过批处理和联机模式执行程序。批处理系统的示例可以通过 VSAM(虚拟存储访问方法)文件处理银行交易并将其应用于相应帐户。联机系统的示例可以是银行职员用于开立帐户的后端屏幕。在批处理模式中,程序通过 JCL 作为作业提交给操作系统。

批处理和联机处理在输入、输出和程序执行请求方面有差异。在批处理中,这些方面被输入 JCL,进而由操作系统接收。

Job Processing

作业是一个工作单元,它可以由许多作业步骤组成。每个作业步骤都通过一组作业控制语句在作业控制语言 (JCL) 中指定。

操作系统使用 Job Entry System (JES) 将作业接收至操作系统、安排处理作业,并控制输出。

作业处理经历如下图所示的一系列步骤:

job processing
  1. Job Submission - 将 JCL 提交至 JES。

  2. Job Conversion - JCL 及其 PROC 会被转换为解释文本,以便 JES 理解并存储到一个数据集(我们称之为 SPOOL)中。

  3. Job Queuing - JES 根据 JOB 语句 (如 JCL - JOB Statement 章节中所述) 中的参数 CLASS 和 PRTY 确定作业的优先级。检查 JCL 错误,如果没有错误,则计划作业进入作业队列。

  4. Job Execution - 当作业达到其最高优先级时,它将从作业队列中执行。从 SPOOL 中读取 JCL,执行程序,并将输出重定向到 JCL 中指定的相应输出目的地。

  5. Purging - 作业完成后,释放分配的资源和 JES SPOOL 空间。为了存储作业日志,我们需要在从 SPOOL 中释放之前将作业日志复制到另一个数据集。

JCL - Environment Setup

Installing JCL on Windows/Linux

有许多可用于 Windows 的免费大型机仿真器,可以用来编写和学习样例 JCL。

其中一个仿真器是 Hercules,它可以通过以下几个简单步骤轻松安装在 Windows 上:

  1. 从 Hercules 主页下载并安装 Hercules 仿真器 - : www.hercules-390.eu

  2. 在 Windows 计算机上安装软件包后,它将创建一个类似 C:\Mainframes 的文件夹。

  3. 运行命令提示符 (CMD),并在 CMD 中到达目录 C:\Mainframes。

  4. 可在 URL www.jaymoseley.com/hercules/installmvs/instmvs2.htm 上找到关于撰写和执行 JCL 的各种命令的完整指南。

除了最新的 64 位 z/Architecture 架构外,Hercules 还是大型机 System/370 和 ESA/390 架构的开源软件实现。Hercules 可以在 Linux、Windows、Solaris、FreeBSD 和 Mac OS X 下运行。

Running JCL on Mainframes

用户可以通过多种方式连接到大型机服务器,例如精简型客户端、虚拟终端、虚拟客户机系统 (VCS) 或虚拟桌面系统 (VDS)。

每个有效用户都会获得一个登录 ID,用于进入 Z/OS 界面 (TSO/E 或 ISPF)。在 Z/OS 界面中,可以对 JCL 进行编码并将其存储为分区数据集 (PDS) 中的成员。提交 JCL 时,它将执行,并且输出将接收,如前一章的作业处理部分中所述。

Structure of a JCL

下面给出了包含通用语句的基本 JCL 结构:

//SAMPJCL JOB 1,CLASS=6,MSGCLASS=0,NOTIFY=&SYSUID          (1)
//*                                                        (2)
//STEP010  EXEC PGM=SORT                                   (3)
//SORTIN   DD DSN=JCL.SAMPLE.INPUT,DISP=SHR                (4)
//SORTOUT  DD DSN=JCL.SAMPLE.OUTPUT,                       (5)
//         DISP=(NEW,CATLG,CATLG),DATACLAS=DSIZE50
//SYSOUT   DD SYSOUT=*                                     (6)
//SYSUDUMP DD SYSOUT=C                                     (6)
//SYSPRINT DD SYSOUT=*                                     (6)
//SYSIN    DD *                                            (6)
  SORT FIELDS=COPY
  INCLUDE COND=(28,3,CH,EQ,C'XXX')
/*                                                         (7)

Program Description

编号的 JCL 语句已在下面加以说明:

(1) JOB statement - 指定作业 SPOOLing 所需的信息,例如作业 ID、执行优先级、作业完成后通知的用户 ID。

(2) // 语句* - 这是一个注释语句。

(3) EXEC statement - 指定要执行的 PROC/程序。在上面的示例中,正在执行一个 SORT 程序(即按特定顺序对输入数据进行排序)

(4) Input DD statement - 指定要传递给 (3) 中所述程序的输入类型。在上面的示例中,物理顺序 (PS) 文件作为共享模式中的输入传递 (DISP = SHR)。

(5) Output DD statement - 指定执行程序后要生成的输出类型。在上面的示例中,创建了 PS 文件。如果一条语句超过一行中的第 70 个位置,那么在下一行中继续该语句,下一行应以 “//” 加一个或多个空格开头。

(6) 还可以使用其他类型的 DD 语句来向程序指定其他信息(在上述示例中:在 SYSIN DD 语句中指定排序条件),并指定错误/执行日志(示例:SYSUDUMP/SYSPRINT)的目的地。DD 语句可以包含在数据集(大型机文件)中,也可以包含在流式数据中(在 JCL 中硬编码的信息),如上述示例所示。

(7) / * 标记流式数据结束。

除流式数据外,所有 JCL 语句均以 // 开头。JOB、EXEC 和 DD 关键字之前和之后至少要有一个空格,语句其余部分不应有任何空格。

JOB Parameter Types

每个 JCL 语句都附带一组参数,以帮助操作系统完成程序执行。参数可以分为两种类型:

Positional Parameters

  1. 出现在语句的预定义位置和顺序中。示例:记帐信息参数只能出现在 JOB 关键字之后,在程序员姓名参数和关键字参数之前。如果省略位置参数,必须用逗号代替。

  2. JOB 和 EXEC 语句中存在位置参数。在上面的示例中,PGM 是 EXEC 关键字后面编码的位置参数。

Keyword Parameters

  1. 它们在位置参数之后编码,但可以按任何顺序出现。如果不需要,可以省略关键字参数。通用语法是 KEYWORD=value。示例:MSGCLASS=X,即作业日志在作业完成后的输出 SPOOL 中重定向。

  2. 在上述示例中,CLASS、MSGCLASS 和 NOTIFY 是 JOB 语句的关键字参数。EXEC 语句中也可以有关键字参数。

这些参数将在后续章节中详细列出,并附有适当的示例。

JCL - JOB Statement

JOB 语句是 JCL 中的第一个控制语句。这给了操作系统 (OS) 对作业的身份,在后台和计划程序中。JOB 语句中的参数帮助操作系统分配正确的计划程序、所需的 CPU 时间并向用户发出通知。

Syntax

以下是 JCL JOB 语句的基本语法:

//Job-name JOB Positional-param, Keyword-param

Description

让我们看看上面 JOB 语句语法中使用的术语的描述。

Job-name

在将作业提交给操作系统时,这会给作业一个 ID。其长度可以是 1 到 8 个字母数字字符,并且紧跟 // 之后开始。

JOB

这是识别它为 JOB 语句的关键字。

Positional-param

存在以下位置参数,它们可以分为两种类型:

Positional Parameter

Description

Account information

这指定 CPU 时间所欠的个人或组别。它根据拥有大型机的公司的规则进行设置。如果将其指定为 (*),则它将取当前登录到大型主机终端用户的 ID。

Programmer name

这识别了负责 JCL 的个人或组别。这不是必填参数,可以用逗号代替。

Keyword-param

以下是可以在 JOB 语句中使用的各种关键字参数。您可以根据需要使用一个或多个参数,并用逗号分隔它们:

Keyword Parameter

Description

CLASS

根据作业所需的时间和资源数量,各公司分配不同的作业类别。这些可以看作 OS 用于接收作业的单独调度程序。将作业放在正确的调度程序中将有助于轻松执行作业。某些公司对测试和生产环境中的作业有不同的类别。CLASS 参数的有效值为字符 A 到 Z 和数字 0 到 9(长度为 1)。以下是语法:*CLASS=0 到 9

A to Z*

PRTY

用于指定一个作业类别内的作业优先级。如果未指定此参数,则将作业添加到指定 CLASS 队列的末尾。以下是语法: PRTY=N 其中 N 是介于 0 到 15 之间的一个数字,数字越大,优先级越高。

NOTIFY

系统会将成功或失败消息(最大条件代码)发送到此参数中指定的用户。以下是语法:*NOTIFY="userid

&SYSUID"*此处系统将消息发送到用户“userid”,但如果我们使用 NOTIFY = &SYSUID,则消息将发送给提交 JCL 的用户。

MSGCLASS

用于在作业完成后指定系统和作业消息的输出目标。以下是语法: MSGCLASS=CLASS CLASS 的有效值可以是“A”到“Z”和“0”到“9”。可以将 MSGCLASS = Y 设置为一个类别,以将作业日志发送到 JMR(作业日志管理和检索:大型机中的存储作业统计数据的储存库)。

MSGLEVEL

指定要写入在 MSGCLASS 中指定的输出目标的消息类型。以下是语法: MSGLEVEL=(ST, MSG) ST = 写入输出日志的语句类型当 ST = 0 时,仅限作业语句。当 ST = 1 时,JCL 以及展开的符号参数。当 ST = 2 时,仅限输入 JCL。MSG = 写入输出日志的消息类型。当 MSG = 0 时,在作业异常完成时写入分配和终止消息。当 MSG = 1 时,无论作业完成的性质如何,都会写入分配和终止消息。

TYPRUN

指定对作业的特殊处理。以下是语法:*TYPRUN = SCAN

HOLD*其中 SCAN 和 HOLD 的描述如下:TYPRUN = SCAN 在不执行 JCL 的情况下检查其语法错误。TYPRUN = HOLD 将作业置于作业队列中。要释放作业,可以在 SPOOL 中针对作业输入“A”,这会将作业带入执行。

TIME

指定处理器用于执行作业的时间跨度。以下是语法: TIME=(mm, ss) or TIME=ss 其中 mm = 分钟,ss = 秒此参数在测试新编码的程序时很有用。为了确保程序不会因循环错误而长时间运行,可以编码一个时间参数,以便在达到指定的 CPU 时间时使程序异常终止。

REGION

指定在作业中运行作业步所需的地址空间。以下是语法:*REGION=nK

nM*此处,区域可以指定为 nK 或 nM,其中 n 为数字,K 为千字节,M 为兆字节。当 REGION = 0K 或 0M 时,将为执行提供最大的地址空间。在关键应用程序中,禁止编码 0K 或 0M 以避免浪费地址空间。

Example

//URMISAMP JOB (*),"tutpoint",CLASS=6,PRTY=10,NOTIFY=&SYSUID,
//   MSGCLASS=X,MSGLEVEL=(1,1),TYPRUN=SCAN,
//   TIME=(3,0),REGION=10K

此处,JOB 语句被扩展到一行中的第 70 个位置之后,因此我们继续下一行,该行应从“//”后面接一个或多个空格开始。

Miscellaneous Parameters

还有其他一些参数可与 JOB 语句一起使用,但它们并不常用:

ADDRSPC

使用的存储类型:虚拟或实际

BYTES

要写入输出日志的数据大小以及在超出此大小时要执行的操作。

LINES

要打印到输出日志的最大行数。

PAGES

要打印到输出日志的最大页数。

USER

用于提交作业的用户 ID

PASSWORD

USER 参数中指定的用户 ID 的密码。

COND and RESTART

这些用于条件作业步骤处理,并在讨论条件处理时详细解释。

JCL - EXEC Statement

每个 JCL 可以由多个作业步骤组成。每个作业步骤都可以直接执行一个程序,或者可以调用一个过程,该过程又执行一个或多个程序(作业步骤)。包含作业步骤程序/过程信息的语句是 EXEC statement.

EXEC 语句的目的是为作业步骤中执行的程序/过程提供所需信息。在此语句中编码的参数可以将数据传递给正在执行的程序,可以覆盖 JOB 语句的某些参数,并且可以在 EXEC 语句调用过程而不是直接执行程序的情况下将参数传递给过程。

Syntax

以下为 JCL EXEC 语句的基本语法:

//Step-name EXEC Positional-param, Keyword-param

Description

让我们了解以上 EXEC 语句语法中所用术语的描述。

STEP-NAME

这标识 JCL 中的作业步骤。它可以是包含字母数字字符的长度为 1 到 8 的字符串。

EXEC

这是将其标识为 EXEC 语句的关键字。

POSITIONAL-PARAM

这些是位置参数,可以是两种类型:

Positional Parameter

Description

PGM

这指的是将在作业步骤中执行的程序名称。

PROC

这指的是将在作业步骤中执行的步骤名称。我们将在单独一章中对其进行讨论。

KEYWORD-PARAM

以下是 EXEC 语句的各种关键字参数。您可以根据需求使用一个或多个参数,并且它们以逗号分隔:

Keyword Parameter

Description

PARM

用于向在作业步骤中执行的程序提供参数化数据。这是一个程序相关字段,没有明确的规则,只是如果 PARM 值包含特殊字符则必须将其包含在引号中。例如在下面给出的示例中,值“CUST1000”将作为一个字母数字值传给该程序。如果该程序是 COBOL 程序,则该程序可通过程序的 LINKAGE SECTION 接收 JCL 的 PARM 参数中传递过来的值。

ADDRSPC

这用于指定作业步骤是需要虚拟存储还是实际存储来执行。虚拟存储是可分页的,而实际存储不是,并且被放入主内存中以供执行。需要更快执行的作业步骤可以存储在实际存储中。以下是语法:*ADDRSPC=VIRT

REAL*如果未编码 ADDRSPC,则 VIRT 为默认值。

ACCT

Common Keyword Parameters of EXEC and JOB Statement

Keyword Parameter

Description

ADDRSPC

JOB 语句中编码的 ADDRSPC 会覆盖任何作业步骤的 EXEC 语句中编码的 ADDRSPC。

TIME

如果在 EXEC 语句中编码了 TIME,则它仅适用于该作业步骤。如果它同时在 JOB 和 EXEC 语句中被指定,则两者都会生效,并且可能由于其中任何一个的原因导致超时错误。不建议在 JOB 和 EXEC 语句中同时使用 TIME 参数。

REGION

REGION 如果在 EXEC 语句中编码,则仅适用于该作业步骤。JOB 语句中编码的 REGION 会覆盖任何作业步骤的 EXEC 语句中编码的 REGION。

COND

用于根据上一步的返回码来控制作业步骤执行。如果在作业步骤的 EXEC 语句中编码了 COND 参数,则 JOB 语句的 COND 参数(如果存在)将被忽略。使用 COND 参数可以执行的各种测试在条件处理中进行了说明。

Example

以下是带有 JOB 和 EXEC 语句的 JCL 脚本的一个简单示例:

//TTYYSAMP JOB 'TUTO',CLASS=6,MSGCLASS=X,REGION=8K,
//      NOTIFY=&SYSUID
//*
//STEP010 EXEC PGM=MYCOBOL,PARAM=CUST1000,
//      ACCT=(XXXX),REGION=8K,ADDRSPC=REAL,TIME=1440

JCL - DD Statement

数据集是记录采用特定格式组织的主机文件。数据集存储在主机的直接访问存储器设备 (DASD) 或磁带上,并且是基本数据存储区域。如果需要在批处理程序中使用/创建这些数据,则 JCL 中会编码文件(即数据集)物理名称以及文件格式和组织。

使用 JCL 中使用的每个数据集的定义 DD statement 。作业步骤所需的输入输出资源需要在一个 DD 语句中进行描述,其中包含诸如数据集组织、存储要求和记录长度等信息。

Syntax

以下是 JCL DD 语句的基本语法:

//DD-name DD Parameters

Description

让我们了解上述 DD 语句语法中使用的术语的描述。

DD-NAME

DD-NAME 标识数据集或输入/输出资源。如果这是 COBOL/汇编程序使用的输入/输出文件,则该程序内会通过此名称引用文件。

DD

这是用作 DD 语句的标识符的关键字。

PARAMETERS

以下是 DD 语句的各种参数。你可以根据需要使用一个或多个参数,这些参数由逗号分隔:

Parameter

Description

DSN

DSN 参数引用新创建或现有数据集的物理数据集名称。DSN 值可以由以下部分组成:每个部分长度为 1 到 8 个字符,由句点分隔,总长度为 44 个字符(字母数字字符)。以下是语法: DSN=Physical Dataset Name Temporary datasets 所需的存储空间仅用于作业持续时间,并在作业完成后删除。此类数据集表示为 DSN=&name * or simply without a DSN specified. If a temporary dataset created by a job step is to be used in the next job step, then it is referenced as *DSN= .stepname.ddname*。这称为 向后引用

DISP

DISP 参数用于描述数据集的状态,正常或异常完成时作业步骤结束时的处理方式。仅当在同一作业步骤中创建并删除数据集时,DD 语句才不需要 DISP(例如临时数据集)。以下为语法:* DISP=(status, normal-disposition, abnormal-disposition)* status 的有效值为: NEW :数据集由作业步骤新建。示例中为 OUTPUT1。 OLD :数据集已创建,将在作业步骤中覆盖。作业步骤获得该数据集的独占访问权,在作业步骤完成之前,其他作业均无法访问该数据集。 SHR :数据集已创建,将在作业步骤中读取。该数据集可以同时被多个作业读取。示例:INPUT1 和 INPUT2。 MOD :数据集已创建。在需要向现有数据集追加新记录时(不会覆盖现有记录)将使用此处理方式。 normal-disposition 参数可以采用以下值:CATLG、UNCATLG、DELETE、PASS 和 KEEP abnormal-disposition 参数可以采用以下值:CATLG、UNCATLG、DELETE 和 KEEP以下是 CATLG、UNCATLG、DELETE、PASS 和 KEEP 参数的说明: CATLG :数据集连同系统目录中的一个条目一起保留。 UNCATLG :数据集被保留,但系统目录条目被删除。 KEEP :数据集被保留,而不更改任何目录条目。KEEP 仅对 VSAM 文件有效。这仅用于永久数据集。 DELETE :数据集从用户和系统目录中删除。 PASS :仅对正常处理方式有效。在 JCL 中将数据集传递至下一步作业处理时使用此处理方式。当未指定 DISP 的任何子参数时,默认值如下: status :NEW 为默认值。 normal-disposition :如果状态为 NEW,则默认正常处理方式为 DELETE,否则为 KEEP。 abnormal-disposition :与正常处理方式相同。

DCB

数据控制块 (DCB) 参数详细说明了数据集的物理特性。此参数对于作业步骤中新建的数据集是必需的。LRECL 是数据集中每条记录的长度。RECFM 是数据集的记录格式。RECFM 可以包含值 FB、V 或 VB。FB 是固定块组织,其中一个或多个逻辑记录被分组到一个块内。V 是可变组织,其中一个可变长度逻辑记录被放置到一个物理块内。VB 是可变块组织,其中一个或多个可变长度逻辑记录被放置到一个物理块内。BLKSIZE 是物理块的大小。块越大,对于 FB 或 VB 文件,记录就越多。DSORG 是数据集组织的类型。DSORG 可以包含值 PS(物理顺序)、PO(分隔组织)和 DA(直接组织)。当需要在同一作业步骤或 JCL 中将一个数据集的 DCB 值复制到另一个数据集时,则将其指定为 DCB=*.stepname.ddname,其中 stepname 是作业步骤的名称,ddname 是从中复制 DCB 的数据集。查看以下示例,其中 RECFM=FB,LRECL=80 形成数据集 OUTPUT1 的 DCB。

SPACE

SPACE 参数指定 DASD(直接访问存储器磁盘)中数据集所需的容量。以下是语法: SPACE=(spcunits, (pri, sec, dir), RLSE) 以下是所有已使用的参数的描述: spcunits :可以是 CYL(圆柱体)、TRK(磁道)或 BLKSIZE(块大小)之一。 pri :这是数据集所需的主存储空间。 sec :这是在主空间不足时所需的附加容量。 ir :如果是 PDS(分区数据集)且其中有成员,这是所需的目录块。 RLSE :这用于在作业完成后释放未使用的空间。

UNIT

UNIT 和 VOL 参数列在已编录数据集的系统目录中,因此仅使用物理 DSN 名称即可访问它们。但对于未编录数据集,DD 语句应包括这些参数。对于要创建的新数据集,可以指定 UNIT/VOL 参数或让 Z/OS 分配合适的设备和卷。UNIT 参数指定存储数据集的设备类型。可以使用硬件地址或设备类型组标识设备类型。以下是语法:*UNIT=DASD

SYSDA*其中 DASD 代表直接访问存储器设备,SYSDA 代表系统直接访问,并指下一个可用的磁盘存储设备。

VOL

VOL 参数指定由 UNIT 参数标识的设备上的卷号。以下是语法: VOL=SER=(v1,v2) 其中 v1、v2 是卷序列号。你还可以使用以下语法: VOL=REF= .DDNAME*其中 REF 是对 JCL 中任何先前作业步骤中数据集的卷序列号的反向引用。

SYSOUT

Example

以下是一个示例,利用了 DD 语句以及上面解释的各种参数:

//TTYYSAMP JOB 'TUTO',CLASS=6,MSGCLASS=X,REGION=8K,
//         NOTIFY=&SYSUID
//*
//STEP010  EXEC PGM=ICETOOL,ADDRSPC=REAL
//*
//INPUT1   DD DSN=TUTO.SORT.INPUT1,DISP=SHR
//INPUT2   DD DSN=TUTO.SORT.INPUT2,DISP=SHR,UNIT=SYSDA,
//         VOL=SER=(1243,1244)
//OUTPUT1  DD DSN=MYFILES.SAMPLE.OUTPUT1,DISP=(,CATLG,DELETE),
//         RECFM=FB,LRECL=80,SPACE=(CYL,(10,20))
//OUTPUT2  DD SYSOUT=*

JCL - Base Library

Base Library 是分区数据集 (PDS),它保存要在 JCL 中执行的程序的加载模块或在程序中调用的编录过程。基础库可以针对整个 JCL 在 JOBLIB 库中指定,也可以针对特定作业步骤在 STEPLIB 语句中指定。

JOBLIB Statement

JOBLIB 语句用于标识 JCL 中要执行的程序的位置。在 JOB 语句之后和 EXEC 语句之前指定 JOBLIB 语句。仅可用于流中过程和程序。

Syntax

以下为 JCL JOBLIB 语句的基本语法:

//JOBLIB DD DSN=dsnname,DISP=SHR

JOBLIB 语句适用于 JCL 中的所有 EXEC 语句。将在 EXEC 语句中指定的程序在系统库中搜索,然后在 JOBLIB 库中搜索。

例如,如果 EXEC 语句正在执行一个 COBOL 程序,则 COBOL 程序的加载模块应放在 JOBLIB 库中。

STEPLIB Statement

STEPLIB 语句用于识别任务步骤中要执行的程序的位置。STEPLIB 语句在 EXEC 语句后而且在任务步骤的 DD 语句前指定。

Syntax

以下是 JCL STEPLIB 语句的基本语法:

//STEPLIB DD DSN=dsnname,DISP=SHR

EXEC 语句中指定的程序将在 STEPLIB 库中搜索,然后在系统库中搜索。任务步骤中编码的 STEPLIB 会覆盖 JOBLIB 语句。

Example

以下示例显示了 JOBLIB 和 STEPLIB 语句的用法:

//MYJCL JOB ,,CLASS=6,NOTIFY=&SYSUID
//*
//JOBLIB DD DSN=MYPROC.BASE.LIB1,DISP=SHR
//*
//STEP1 EXEC PGM=MYPROG1
//INPUT1 DD DSN=MYFILE.SAMPLE.INPUT1,DISP=SHR
//OUTPUT1 DD DSN=MYFILES.SAMPLE.OUTPUT1,DISP=(,CATLG,DELETE),
//           RECFM=FB,LRECL=80
//*
//STEP2 EXEC PGM=MYPROG2
//STEPLIB DD DSN=MYPROC.BASE.LIB2,DISP=SHR
//INPUT2 DD DSN=MYFILE.SAMPLE.INPUT2,DISP=SHR
//OUTPUT2 DD DSN=MYFILES.SAMPLE.OUTPUT2,DISP=(,CATLG,DELETE),
//           RECFM=FB,LRECL=80

在此处,在 MYPROC.SAMPLE.LIB1 中搜索程序 MYPROG1 的加载模块(在 STEP1 中)。如果找不到,它将在系统库中搜索。在 STEP2 中,STEPLIB 覆盖了 JOBLIB,并且在 MYPROC.SAMPLE.LIB2 中搜索程序 MYPROG2 的加载模块,然后在系统库中搜索。

INCLUDE Statement

可以使用 INCLUDE 语句将 PDS 成员中编码的一组 JCL 语句包含到 JCL 中。当 JES 解释 JCL 时,INCLUDE 成员中的 JCL 语句集将替换 INCLUDE 语句。

Syntax

以下是 JCL INCLUDE 语句的基本语法:

//name INCLUDE MEMBER=member-name

INCLUDE 语句的主要目的是可重用性。例如,在许多 JCL 中使用的通用文件可以编码为 INCLUDE 成员中的 DD 语句并用于 JCL 中。

虚拟 DD 语句、数据卡规范、PROC、JOB、PROC 语句不能编码到 INCLUDE 成员中。可以在 INCLUDE 成员中编码 INLCUDE 语句,并且可以进一步嵌套,最多 15 级。

JCLLIB Statement

JCLLIB 语句用于识别作业中使用的私有库。它既可用于流内过程,也可用于编目过程。

Syntax

以下是 JCL JCLLIB 语句的基本语法:

//name JCLLIB ORDER=(library1, library2....)

JCLLIB 语句中指定的库将按给定的顺序进行搜索,以找到作业中使用的程序、过程和 INCLUDE 成员。JCL 中只能有一个 JCLLIB 语句;指定在 JOB 语句之后且在 EXEC 和 INCLUDE 语句之前,但不能编码到 INCLUDE 成员中。

Example

在以下示例中,将按 MYPROC.BASE.LIB1、MYPROC.BASE.LIB2、系统库的顺序搜索程序 MYPROG3 和 INCLUDE 成员 MYINCL。

//MYJCL JOB ,,CLASS=6,NOTIFY=&SYSUID
//*
//MYLIB JCLLIB ORDER=(MYPROC.BASE.LIB1,MYPROC.BASE.LIB2)
//*
//STEP1 EXEC PGM=MYPROG3
//INC INCLUDE MEMBER=MYINCL
//OUTPUT1 DD DSN=MYFILES.SAMPLE.OUTPUT1,DISP=(,CATLG,DELETE),
//           RECFM=FB,LRECL=80
//*

JCL - Procedures

JCL Procedures 是一组 JCL 内的语句,组合在一起执行特定功能。通常,JCL 的固定部分在过程中编码。作业的可变部分在 JCL 内编码。

你可以使用过程来使用多个输入文件实现程序的并行执行。可以为每个输入文件创建一个 JCL,并且可以通过将输入文件名作为符号参数传递来同时调用单个过程。

Syntax

以下是 JCL 过程定义的基本语法:

//*
//Step-name EXEC procedure name

对于流内过程,过程内容保存在 JCL 中。对于编目过程,内容保存在基本库的其他成员中。本章将说明 JCL 中可用的两种类型过程,然后最终我们将看到如何嵌套各种过程。

Instream Procedure

当过程在同一 JCL 成员内编码时,称之为流内过程。它应该以 PROC 语句开始并以 PEND 语句结束。

//SAMPINST JOB 1,CLASS=6,MSGCLASS=Y,NOTIFY=&SYSUID
//*
//INSTPROC   PROC                //*START OF PROCEDURE
//PROC1		EXEC PGM=SORT
//SORTIN	DD DSN=&DSNAME,DISP=SHR
//SORTOUT	DD SYSOUT=*MYINCL
//SYSOUT	DD SYSOUT=*
//SYSIN		DD DSN=&DATAC LRECL=80
//           PEND               //*END OF PROCEDURE
//*
//STEP1      EXEC INSTPROC,DSNME=MYDATA.URMI.INPUT1,
//           DATAC=MYDATA.BASE.LIB1(DATA1)
//*
//STEP2      EXEC INSTPROC,DSNME=MYDATA.URMI.INPUT2
//           DATAC=MYDATA.BASE.LIB1(DATA1)
//*

在以上示例中,在 STEP1 和 STEP2 中使用不同的输入文件调用了过程 INSTPROC。在调用过程时,可以使用不同的值对参数 DSNAME 和 DATAC 进行编码,这些称为 symbolic parameters 。输入到 JCL 的变量(如文件名、数据卡、PARM 值等)作为符号参数传递给过程。

在编码符号参数时,不要将关键字、参数或子参数用作符号名称。示例:不要使用 TIME=&TIME,而是可以使用 TIME=&TM,这被视为编码符号的正确方法。

用户定义的符号参数称为 JCL Symbols 。有一些符号称为 system symbols ,它们用于日志记录作业执行。普通用户在批处理作业中唯一使用的系统符号是 &SYSUID ,它在 JOB 语句中的 NOTIFY 参数中使用。

Cataloged Procedure

当过程从 JCL 中分离出来并在不同的数据存储器中编码时,它被称为 Cataloged Procedure 。CATALOGed 过程中不必强制编码 PROC 语句。以下是一个 JCL 示例,其中它调用 CATLPROC 过程:

//SAMPINST JOB 1,CLASS=6,MSGCLASS=Y,NOTIFY=&SYSUID
//*
//STEP EXEC CATLPROC,PROG=CATPRC1,DSNME=MYDATA.URMI.INPUT
//          DATAC=MYDATA.BASE.LIB1(DATA1)

在这里,过程 CATLPROC 在 MYCOBOL.BASE.LIB1 中编入目录。PROG、DATAC 和 DSNAME 作为符号参数传递给 CATLPROC 过程。

//CATLPROC PROC PROG=,BASELB=MYCOBOL.BASE.LIB1
//*
//PROC1     EXEC PGM=&PROG
//STEPLIB   DD DSN=&BASELB,DISP=SHR
//IN1       DD DSN=&DSNAME,DISP=SHR
//OUT1      DD SYSOUT=*
//SYSOUT    DD SYSOUT=*
//SYSIN     DD DSN=&DATAC
//*

在过程中,对符号参数 PROG 和 BASELB 进行编码。请注意,过程中 PROG 参数被 JCL 中的值覆盖,因此 PGM 在执行期间获取值 CATPRC1。

Nested Procedures

从过程中调用过程称为 nested procedure 。过程可以嵌套到 15 级。嵌套可以完全在流中进行,也可以编目。我们无法在编目过程中编码流内过程。

//SAMPINST JOB 1,CLASS=6,MSGCLASS=Y,NOTIFY=&SYSUID
//*
//SETNM     SET DSNM1=INPUT1,DSNM2=OUTPUT1
//INSTPRC1  PROC               //* START OF PROCEDURE 1
//STEP1        EXEC PGM=SORT,DISP=SHR
//SORTIN       DD DSN=&DSNM1,DISP=SHR
//SORTOUT      DD DSN=&DSNM2,DISP=(,PASS)
//SYSOUT       DD SYSOUT=*
//SYSIN        DD DSN=&DATAC
//*
//STEP2        EXEC PROC=INSTPRC2,DSNM2=MYDATA.URMI.OUTPUT2
//          PEND               //* END OF PROCEDURE 1
//*
//INSTPRC2  PROC               //* START OF PROCEDURE 2
//STEP1        EXEC PGM=SORT
//SORTIN       DD DSN=*.INSTPRC1.STEP1.SORTOUT
//SORTOUT      DD DSN=&DSNM2,DISP=OLD
//SYSOUT       DD SYSOUT=*
//SYSIN        DD DSN=&DATAC
//          PEND               //* END OF PROCEDURE 2
//*
//JSTEP1    EXEC INSTPRC1,DSNM1=MYDATA.URMI.INPUT1,
//          DATAC=MYDATA.BASE.LIB1(DATA1)
//*

在上面的示例中,JCL 在 JSTEP1 中调用过程 INSTPRC1,并且在过程 INSTPRC1 中调用过程 INSTPRC2。在这里,INSTPRC1(SORTOUT)的输出作为输入(SORTIN)传递给 INSTPRC2。

让我们看看下面的描述,以了解有关上述程序的更多信息:

  1. SET 参数初始化 DSNM1=INPUT1 和 DSNM2=OUTPUT1。

  2. 当在 JCL 的 JSTEP1 中调用 INSTPRC1 时,DSNM1=MYDATA.URMI.INPUT1 和 DSNM2=OUTPUT1,即在任何作业步骤/过程中设置的值都会重置为 SET 语句中初始化的值。

  3. 当在 INSTPRC1 的 STEP2 中调用 INSTPRC2 时,DSNM1=MYDATA.URMI.INPUT1 和 DSNM2=MYDATA.URMI.OUTPUT2。

JCL - Conditional Processing

作业入口系统使用两种方法在 JCL 中执行条件处理。当作业完成时,会根据执行状态设置返回码。返回码可以是介于 0(执行成功)到 4095(非零表示错误状况)之间的数字。最常见的约定值有:

  1. 0 = 正常 - 一切正常

  2. 4 = 警告 - 轻微错误或问题。

  3. 8 = 错误 - 重大错误或问题。

  4. 12 = 严重错误 - 重大错误或问题,结果不可靠。

  5. 16 = 终止错误 - 非常严重的问题,请勿使用结果。

作业步骤执行可以根据 COND * parameter and *IF-THEN-ELSE 结构中解释的先前的步骤的返回码进行控制。

COND parameter

可以在 JCL 的 JOB 或 EXEC 语句中对 COND 参数进行编码。这是对前一个作业步骤返回码的测试。如果对测试评估结果为真,则会绕过当前的作业步骤执行。绕过只是省略作业步骤,而不是执行异常终止。单次测试最多可以合并八个条件。

Syntax

以下是 JCL COND 参数的基本语法:

COND=(rc,logical-operator)
or
COND=(rc,logical-operator,stepname)
or
COND=EVEN
or
COND=ONLY

下面是对所用参数的描述:

  1. rc :此返回值

  2. logical-operator :可能是 GT(大于)、GE(大于或等于)、EQ(等于)、LT(小于)、LE(小于或等于)或 NE(不等于)。

  3. stepname :用于测试的作业步骤的返回码。

最后两个条件 (a) COND=EVEN 和 (b) COND=ONLY 已在本教程中进行了说明。

可以在 JOB 语句或 EXEC 语句中对 COND 进行编码,并且在两种情况下,它都会表现出不同的行为,如下所示:

COND inside JOB statement

当在 JOB 语句中对 COND 进行编码时,会对每个作业步骤测试条件。当条件在任何特定作业步骤中为真时,将会跳过它以及随后的作业步骤。以下是一个示例:

//CNDSAMP JOB CLASS=6,NOTIFY=&SYSUID,COND=(5,LE)
//*
//STEP10 EXEC PGM=FIRSTP
//* STEP10 executes without any test being performed.

//STEP20 EXEC PGM=SECONDP
//* STEP20 is bypassed, if RC of STEP10 is 5 or above.
//* Say STEP10 ends with RC4 and hence test is false.
//* So STEP20 executes and lets say it ends with RC16.

//STEP30 EXEC PGM=SORT
//* STEP30 is bypassed since 5 <= 16.

COND inside EXEC statement

当在作业步骤的 EXEC 语句中对 COND 进行编码并发现为真时,只跳过该作业步骤,并且从下一个作业步骤继续执行。

//CNDSAMP JOB CLASS=6,NOTIFY=&SYSUID
//*
//STP01 EXEC PGM=SORT
//* Assuming STP01 ends with RC0.

//STP02 EXEC PGM=MYCOBB,COND=(0,EQ,STP01)
//* In STP02, condition evaluates to TRUE and step bypassed.

//STP03 EXEC PGM=IEBGENER,COND=((10,LT,STP01),(10,GT,STP02))
//* In STP03, first condition fails and hence STP03 executes.
//* Since STP02 is bypassed, the condition (10,GT,STP02) in
//* STP03 is not tested.

COND=EVEN

当对 COND=EVEN 进行编码时,即使任何以前的步骤异常终止,也将执行当前作业步骤。如果对 COND=EVEN 编码任何其他 RC 条件,那么只有当没有 RC 条件为真时,作业步骤才会执行。

//CNDSAMP JOB CLASS=6,NOTIFY=&SYSUID
//*
//STP01 EXEC PGM=SORT
//* Assuming STP01 ends with RC0.

//STP02 EXEC PGM=MYCOBB,COND=(0,EQ,STP01)
//* In STP02, condition evaluates to TRUE and step bypassed.

//STP03 EXEC PGM=IEBGENER,COND=((10,LT,STP01),EVEN)
//* In STP03, condition (10,LT,STP01) evaluates to true,
//* hence the step is bypassed.

COND=ONLY

当对 COND=ONLY 进行编码时,只有当任何以前的步骤异常终止时,才执行当前作业步骤。如果对 COND=ONLY 编码任何其他 RC 条件,那么只有当没有 RC 条件为真,并且任何以前的作业步骤异常失败时,作业步骤才会执行。

//CNDSAMP JOB CLASS=6,NOTIFY=&SYSUID
//*
//STP01 EXEC PGM=SORT
//* Assuming STP01 ends with RC0.

//STP02 EXEC PGM=MYCOBB,COND=(4,EQ,STP01)
//* In STP02, condition evaluates to FALSE, step is executed
//* and assume the step abends.

//STP03 EXEC PGM=IEBGENER,COND=((0,EQ,STP01),ONLY)
//* In STP03, though the STP02 abends, the condition
//* (0,EQ,STP01) is met. Hence STP03 is bypassed.

IF-THEN-ELSE Construct

控制作业处理的另一种方法是使用 IF-THEN-ELSE 构造。这提供了更灵活和用户友好的条件处理方式。

Syntax

以下是 JCL IF-THEN-ELSE 构造的基本语法:

//name IF condition THEN
list of statements //* action to be taken when condition is true
//name ELSE
list of statements //* action to be taken when condition is false
//name ENDIF

以下是上述 IF-THEN-ELSE 构造中所用术语的描述:

  1. name :这是可选的,名称可以有 1 到 8 个以字母、#、$ 或 @ 开头的字母数字字符。

  2. Condition :条件将具有以下格式: KEYWORD OPERATOR VALUE ,其中 KEYWORDS 可以是 RC(返回码)、ABENDCC(系统或用户完成码)、ABEND、RUN(步骤启动执行)。 OPERATOR 可以是逻辑运算符(AND (&)、OR (|))或关系运算符(<、⇐、>、>=、<>)。

Example

以下是一个显示 IF-THEN-ELSE 用法的简单示例:

//CNDSAMP JOB CLASS=6,NOTIFY=&SYSUID
//*
//PRC1   PROC
//PST1	   EXEC PGM=SORT
//PST2	   EXEC PGM=IEBGENER
//       PEND
//STP01  EXEC PGM=SORT
//IF1    IF STP01.RC = 0 THEN
//STP02     EXEC PGM=MYCOBB1,PARM=123
//       ENDIF
//IF2    IF STP01.RUN THEN
//STP03a    EXEC PGM=IEBGENER
//STP03b    EXEC PGM=SORT
//       ENDIF
//IF3    IF STP03b.!ABEND THEN
//STP04     EXEC PGM=MYCOBB1,PARM=456
//       ELSE
//       ENDIF
//IF4    IF (STP01.RC = 0 & STP02.RC <= 4) THEN
//STP05     EXEC PROC=PRC1
//       ENDIF
//IF5    IF STP05.PRC1.PST1.ABEND THEN
//STP06     EXEC PGM=MYABD
//       ELSE
//STP07     EXEC PGM=SORT
//       ENDIF

让我们尝试深入了解上述程序以更详细地理解它:

  1. STP01 的返回码在 IF1 中进行测试。如果是 0,则执行 STP02。否则,处理转到下一个 IF 语句(IF2)。

  2. 在 IF2 中,如果 STP01 已经开始执行,那么 STP03a 和 STP03b 将被执行。

  3. 在 IF3 中,如果 STP03b 没有 ABEND,那么 STP04 将被执行。在 ELSE 中没有语句。它被称为一个 NULL ELSE 语句。

  4. 在 IF4 中,如果 STP01.RC = 0 且 STP02.RC ⇐4 为 TRUE,那么 STP05 将被执行。

  5. 在 IF5 中,如果 jobstep STP05 中的 PROC PRC1 中的 proc-step PST1 ABEND,那么 STP06 将被执行。否则执行 STP07。

  6. 如果 IF4 求值为 false,那么 STP05 将不会被执行。在这种情况下,IF5 将不会被测试,并且步骤 STP06、STP07 也不会被执行。

如果作业异常终止(例如用户取消作业、作业超时,或者数据集因反向引用被绕过的步骤),那么 IF-THEN-ELSE 将不会被执行。

Setting Checkpoints

你可以在 JCL 程序中使用 SYSCKEOV, 设置检查点数据集,它是一个 DD 语句。

CHKPT 是在 DD 语句中为多卷 QSAM 数据集编码的参数。当 CHKPT 被编码为 CHKPT=EOV 时,将在输入/输出多卷数据集的每个卷的末尾写入一个检查点,该检查点将被写入 SYSCKEOV 语句中指定的数据集中。

//CHKSAMP JOB CLASS=6,NOTIFY=&SYSUID
//*
//STP01     EXEC PGM=MYCOBB
//SYSCKEOV  DD DSNAME=SAMPLE.CHK,DISP=MOD
//IN1       DD DSN=SAMPLE.IN,DISP=SHR
//OUT1      DD DSN=SAMPLE.OUT,DISP=(,CATLG,CATLG)
//          CHKPT=EOV,LRECL=80,RECFM=FB

在上例中,检查点将写入到输出数据集 SAMPLE.OUT 的每个卷的末尾的 SAMPLE.CHK 数据集中。

Restart Processing

你可以在使用 RD parameter 的自动化方式或使用 RESTART parameter 的手动方式重新启动处理。

RD parameter 被编码在 JOB 或 EXEC 语句中,它有助于自动化 JOB/STEP 重新启动,并且可以保存四个值之中的一个值:R、RNC、NR 或 NC。

  1. RD=R 允许自动化重新启动,并且会考虑在 DD 语句的 CHKPT 参数中编码的检查点。

  2. RD=RNC 允许自动化重新启动,但是会覆盖(忽略)CHKPT 参数。

  3. RD=NR 指定作业/步骤无法被自动化重新启动。但是,当它使用 RESTART 参数被手动重新启动时,CHKPT 参数(如果有任何)将被考虑。

  4. RD=NC 不允许自动化重新启动和检查点处理。

如果只需要对指定的异常代码进行自动化重新启动,那么可以在 IBM 系统 parmlib 库的 SCHEDxx 成员中指定该代码。

RESTART parameter 被编码在 JOB 或 EXEC 语句中,它有助于作业/步骤在作业失败后手动重新启动。RESTART 可以附带 checkid,即写入到 SYSCKEOV DD 语句中编码的数据集的检查点。当编码 checkid 时,SYSCHK DD 语句应该被编码为在 JOBLIB 语句(如有任何)之后引用检查点数据集,否则在 JOB 语句之后引用。

//CHKSAMP JOB CLASS=6,NOTIFY=&SYSUID,RESTART=(STP01,chk5)
//*
//SYSCHK    DD DSN=SAMPLE.CHK,DISP=OLD
//STP01     EXEC PGM=MYCOBB
//*SYSCKEOV	DD DSNAME=SAMPLE.CHK,DISP=MOD
//IN1       DD DSN=SAMPLE.IN,DISP=SHR
//OUT1      DD DSN=SAMPLE.OUT,DISP=(,CATLG,CATLG)
//          CHKPT=EOV,LRECL=80,RECFM=FB

在上例中,chk5 是 checkid,即 STP01 在 checkpoint5 处重新启动。请注意,在设置检查点部分解释的先前程序中,添加了一个 SYSCHK 语句,并且 SYSCKEOV 语句被注释掉了。

JCL - Defining Datasets

数据集名称指定文件名称,并且在 JCL 中用 DSN 表示。DSN 参数引用新创建或现有数据集的物理数据集名称。DSN 值可以由每个 1 到 8 个字符长度的不超过 44 个字符(字母数字)的子名称组成,子名称之间用点分隔。以下为语法:

DSN=&name | *.stepname.ddname

Temporary datasets 只需要在作业持续时间内存储,并在作业完成后删除。这些数据集表示为 DSN=&name ,或干脆不指定 DSN。

如果要在下一个作业步骤中使用作业步骤创建的临时数据集,则需要将其引用为 DSN= .stepname.ddname*。这称为 Backward Referencing.

Concatenating Datasets

如果有多个相同格式的数据集,则可以将它们连接起来,并以单个 DD 名称作为程序的输入传递。

//CONCATEX JOB CLASS=6,NOTIFY=&SYSUID
//*
//STEP10    EXEC PGM=SORT
//SORTIN    DD DSN=SAMPLE.INPUT1,DISP=SHR
//          DD DSN=SAMPLE.INPUT2,DISP=SHR
//          DD DSN=SAMPLE.INPUT3,DISP=SHR
//SORTOUT   DD DSN=SAMPLE.OUTPUT,DISP=(,CATLG,DELETE),
//          LRECL=50,RECFM=FB

在上面的示例中,将三个数据集串联起来,作为 SORT 程序的输入传递,在 SORTIN DD 名称中。合并文件,按指定键字段排序,然后写入 SORTOUT DD 名称中的单个输出文件 SAMPLE.OUTPUT。

Overriding Datasets

在标准化的 JCL 中,要执行的程序及其相关数据集被放置在已编目的过程中,该过程在 JCL 中被调用。通常,为了测试目的或为了解决事件,可能需要使用不同于编目过程中指定的数据集。在这种情况下,可以覆盖 JCL 中的过程中的数据集。

//SAMPINST JOB 1,CLASS=6,MSGCLASS=Y,NOTIFY=&SYSUID
//*
//JSTEP1    EXEC CATLPROC,PROG=CATPRC1,DSNME=MYDATA.URMI.INPUT
//          DATAC=MYDATA.BASE.LIB1(DATA1)
//STEP1.IN1 DD DSN=MYDATA.OVER.INPUT,DISP=SHR
//*
//* The cataloged procedure is as below:
//*
//CATLPROC PROC PROG=,BASELB=MYCOBOL.BASE.LIB1
//*
//STEP1     EXEC PGM=&PROG
//STEPLIB   DD DSN=&BASELB,DISP=SHR
//IN1       DD DSN=MYDATA.URMI.INPUT,DISP=SHR
//OUT1      DD SYSOUT=*
//SYSOUT    DD SYSOUT=*
//SYSIN     DD MYDATA.BASE.LIB1(DATA1),DISP=SHR
//*
//STEP2     EXEC PGM=SORT

在上面的示例中,数据集 IN1 在 PROC 中使用文件 MYDATA.URMI.INPUT,该文件在 JCL 中被覆盖。因此,执行中使用输入文件 MYDATA.OVER.INPUT。请注意,该数据集被称为 STEP1.IN1。如果 JCL/PROC 中只有一步,那么可以使用仅包含 DD 名称来引用该数据集。类似地,如果 JCL 中有多个步骤,则数据集应覆盖为 JSTEP1.STEP1.IN1。

//SAMPINST  JOB 1,CLASS=6,MSGCLASS=Y,NOTIFY=&SYSUID
//*
//STEP      EXEC CATLPROC,PROG=CATPRC1,DSNME=MYDATA.URMI.INPUT
//          DATAC=MYDATA.BASE.LIB1(DATA1)
//STEP1.IN1 DD DSN=MYDATA.OVER.INPUT,DISP=SHR
//          DD DUMMY
//          DD DUMMY
//*

在上面的示例中,在 IN1 中串联的三个数据集中,第一个被 JCL 覆盖,其余部分保持为 PROC 中存在的。

Defining GDGs in a JCL

生成数据组 (GDG) 是通过公用名相互关联的数据集组。公用名被称为 GDG 基,与该基关联的每个数据集被称为 GDG 版本。

例如,MYDATA.URMI.SAMPLE.GDG 是 GDG 基名称。数据集命名为 MYDATA.URMI.SAMPLE.GDG.G0001V00、MYDATA.URMI.SAMPLE.GDG.G0002V00 等。GDG 的最新版本称为 MYDATA.URMI.SAMPLE.GDG(0),之前的版本称为 (-1)、(-2) 等。将在程序中创建的下一个版本在 JCL 中称为 MYDATA.URMI.SAMPLE.GDG(+1)。

Create/ Alter GDG in a JCL

GDG 版本可以有相同或不同的 DCB 参数。可以定义一个初始模型 DCB 供所有版本使用,但在创建新版本时可以覆盖该模型。

//GDGSTEP1 EXEC PGM=IDCAMS
//SYSPRINT DD  SYSOUT=*
//SYSIN    DD  *
           DEFINE GDG(NAME(MYDATA.URMI.SAMPLE.GDG)   -
           LIMIT(7)                           -
           NOEMPTY                            -
           SCRATCH)
/*
//GDGSTEP2 EXEC PGM=IEFBR14
//GDGMODLD DD  DSN=MYDATA.URMI.SAMPLE.GDG,
//         DISP=(NEW,CATLG,DELETE),
//         UNIT=SYSDA,
//         SPACE=(CYL,10,20),
//         DCB=(LRECL=50,RECFM=FB)
//

在上面的示例中,IDCAMS 实用程序使用在 SYSIN DD 语句中传递的以下参数来定义 GDGSTEP1 中的 GDG 基:

  1. NAME 指定 GDG 基的物理数据集名称。

  2. LIMIT 指定 GDG 基可以持有的最大版本数。

  3. EMPTY 在达到 LIMIT 时取消编录所有代。

  4. NOEMPTY 取消编录最近的代。

  5. SCRATCH 在取消编录代时物理删除该代。

  6. NOSCRATCH 不要删除数据集,也就是说,可以使用 UNIT 和 VOL 参数引用它。

在 GDGSTEP2 中,IEFBR14 实用程序指定所有版本要使用的模型 DD 参数。

IDCAMS 可用于更改 GDG 的定义参数,例如增加 LIMIT,将 EMPTY 更改为 NOEMPTY 等,以及使用 SYSIN 命令更改其相关版本,即 ALTER MYDATA.URMI.SAMPLE.GDG LIMIT(15) EMPTY

Delete GDG in a JCL

使用 IEFBR14 实用程序,我们可以删除 GDG 的单个版本。

//GDGSTEP3   EXEC PGM=IEFBR14
//GDGDEL     DD  DSN=MYDATA.URMI.SAMPLE.GDG(0),
//           DISP=(OLD,DELETE,DELETE)

在上述示例中,MYDATA.URMI.SAMPLE.GDG 的最新版本会被删除。请注意,正常作业完成时的 DISP 参数编码为 DELETE。因此,当作业完成执行时,数据集会被删除。

可以使用 IDCAMS,使用 SYSIN 命令 DELETE(MYDATA.URMI.SAMPLE.GDG) GDG FORCE/PURGE 来删除 GDG 及其相关版本。

  1. FORCE 删除 GDG 版本和 GDG 基线。如果任何 GDG 版本设置的到期日期尚未到期,那么这些版本就不会被删除,因此 GDG 基线会被保留。

  2. PURGE 忽略到期日期,删除 GDG 版本和 GDG 基线。

Using GDG in a JCL

在以下示例中,MYDATA.URMI.SAMPLE.GDG 的最新版本被用作程序的输入,并创建一个 MYDATA.URMI.SAMPLE.GDG 的新版本作为输出。

//CNDSAMP JOB CLASS=6,NOTIFY=&SYSUID
//*
//STP01   EXEC PGM=MYCOBB
//IN1     DD DSN=MYDATA.URMI.SAMPLE.GDG(0),DISP=SHR
//OUT1    DD DSN=MYDATA.URMI.SAMPLE.GDG(+1),DISP=(,CALTG,DELETE)
//        LRECL=100,RECFM=FB

此处,如果 GDG 被实际名称引用,例如 MYDATA.URMI.SAMPLE.GDG.G0001V00,则会导致每次执行前更改 JCL。使用 (0) 和 (+1) 使它在执行时动态地替换 GDG 版本。

Input-Output Methods

通过 JCL 执行的任何批处理程序都需要数据输入,该输入会被处理,并创建一个输出。有不同的方法可向程序提供输入,并编写从 JCL 收到的输出。在批处理模式中,不需要用户交互,但输入和输出设备以及必需的组织在 JCL 中被定义并提交。

Data Input in a JCL

有各种方法可以使用 JCL 向程序提供数据,这些方法在下文中已经进行了说明:

INSTREAM DATA

可以通过 SYSIN DD 语句指定程序中的流数据。

//CONCATEX JOB CLASS=6,NOTIFY=&SYSUID
//* Example 1:
//STEP10 EXEC PGM=MYPROG
//IN1    DD DSN=SAMPLE.INPUT1,DISP=SHR
//OUT1   DD DSN=SAMPLE.OUTPUT1,DISP=(,CATLG,DELETE),
//       LRECL=50,RECFM=FB
//SYSIN  DD *
//CUST1  1000
//CUST2  1001
/*
//*
//* Example 2:
//STEP20 EXEC PGM=MYPROG
//OUT1   DD DSN=SAMPLE.OUTPUT2,DISP=(,CATLG,DELETE),
//       LRECL=50,RECFM=FB
//SYSIN  DD DSN=SAMPLE.SYSIN.DATA,DISP=SHR
//*

在示例 1 中,通过 SYSIN 向 MYPROG 传递输入。数据在 JCL 内提供。两个数据记录传递至程序。请注意,/* 标记流 SYSIN 数据的结束。

“CUST1 1000”是记录 1,“CUST2 1001”是记录 2。在读取数据时遇到符号 /* 时满足数据结束条件。

在示例 2 中,SYSIN 数据保存在数据集内,其中 SAMPLE.SYSIN.DATA 是一个 PS 文件,它可以保存一个或多个数据记录。

Data Input through files

如前几章中的大多数示例所述,程序的数据输入可以通过 PS、VSAM 或 GDG 文件提供,并带有 DD 语句中相关 DSN 名称和 DISP 参数。

在示例 1 中,SAMPLE.INPUT1 是数据通过它传递给 MYPROG 的输入文件。它在程序内被称为 IN1。

Data Output in a JCL

JCL 中的输出可以编入数据集或传递到 SYSOUT。如 DD 语句章节中所述, SYSOUT= * 将输出重定向到与 JOB 语句的 MSGCLASS 中提到的类相同的类。

Saving Job Logs

指定 MSGCLASS=Y 可将作业日志保存在 JMR(作业日志管理和检索)中。整个作业日志可以被重定向到 SPOOL,并且可以通过针对 SPOOL 中的作业名称发出 XDC 命令来将其保存到数据集。当在 SPOOL 中发出 XDC 命令时,将打开一个数据集创建屏幕。然后,可以通过给出适当的 PS 或 PDS 定义来保存作业日志。

作业日志也可以通过指定为 SYSOUT 和 SYSPRINT 提供一个已经创建的数据集来保存。但是,通过这种方式无法捕获整个作业日志(即 JESMSG 将不会被编入目录),就像在 JMR 或 XDC 中那样。

//SAMPINST JOB 1,CLASS=6,MSGCLASS=Y,NOTIFY=&SYSUID
//*
//STEP1    EXEC PGM=MYPROG
//IN1      DD DSN=MYDATA.URMI.INPUT,DISP=SHR
//OUT1     DD SYSOUT=*
//SYSOUT   DD DSN=MYDATA.URMI.SYSOUT,DISP=SHR
//SYSPRINT DD DSN=MYDATA.URMI.SYSPRINT,DISP=SHR
//SYSIN    DD MYDATA.BASE.LIB1(DATA1),DISP=SHR
//*
//STEP2    EXEC PGM=SORT

在上述示例中,SYSOUT 被编入 MYDATA.URMI.SYSOUT,SYSPRINT 被编入 MYDATA.URMI.SYSPRINT。

Running COBOL Programs using JCL

Compiling COBOL Programs

要在批处理模式下使用 JCL 执行一个 COBOL 程序,需要编译该程序,并使用所有子程序创建一个加载模块。JCL 使用加载模块,而不是在执行时间使用实际程序。加载库会被连接起来,并在执行时间使用 JCLLIBSTEPLIB 提供给 JCL。

有多个大型机编译器实用工具可用于编译 COBOL 程序。一些企业公司使用 Endevor 等变更管理工具,该工具可以编译和存储程序的每个版本。这对于跟踪对程序所做的变更非常有用。

//COMPILE   JOB ,CLASS=6,MSGCLASS=X,NOTIFY=&SYSUID
//*
//STEP1     EXEC IGYCRCTL,PARM=RMODE,DYNAM,SSRANGE
//SYSIN     DD DSN=MYDATA.URMI.SOURCES(MYCOBB),DISP=SHR
//SYSLIB    DD DSN=MYDATA.URMI.COPYBOOK(MYCOPY),DISP=SHR
//SYSLMOD   DD DSN=MYDATA.URMI.LOAD(MYCOBB),DISP=SHR
//SYSPRINT  DD SYSOUT=*
//*

IGYCRCTL 是一个 IBM COBOL 编译器实用工具。通过 PARM 参数传递编译器选项。在上述示例中,RMODE 指示编译器在程序中使用相对寻址模式。使用 SYSIN 参数传递 COBOL 程序,并且复用库是由 SYSLIB 中的程序使用的库。

该 JCL 以加载模块作为输出,生成该程序,该加载模块被用作执行 JCL 的输入。

Running COBOL Programs

以下是一个 JCL 示例,其中使用输入文件 MYDATA.URMI.INPUT 执行程序 MYPROG,并生成两个输出文件,这些文件被写入卷。

//COBBSTEP  JOB CLASS=6,NOTIFY=&SYSUID
//
//STEP10    EXEC PGM=MYPROG,PARM=ACCT5000
//STEPLIB   DD DSN=MYDATA.URMI.LOADLIB,DISP=SHR
//INPUT1    DD DSN=MYDATA.URMI.INPUT,DISP=SHR
//OUT1      DD SYSOUT=*
//OUT2      DD SYSOUT=*
//SYSIN     DD *
//CUST1     1000
//CUST2     1001
/*

MYPROG 的加载模块位于 MYDATA.URMI.LOADLIB 中。需要注意的是,上述 JCL 只能用于非 DB2 COBOL 模块。

Passing Data to COBOL Programs

数据输入 COBOL 批处理程序可以通过文件、PARAM 参数和 SYSIN DD 语句进行。在上文示例中:

  1. 通过文件 MYDATA.URMI.INPUT 将数据记录传递给 MYPROG。该文件将在程序中使用 DD 名称 INPUT1 进行引用。可以在程序中打开、读取和关闭该文件。

  2. 链接段将 PARM 参数数据 ACCT5000 接收在程序 MYPROG 的 LINKAGE 段中,其中定义了一个变量。

  3. 程序过程分段中的 ACCEPT 语句会接收 SYSIN 语句中的数据。每个 ACCEPT 语句都会将一个完整记录(即 CUST1 1000)读入到程序中定义的某个工作存储变量中。

Running a COBOL-DB2 program

要运行 COBOL DB2 程序,JCL 和程序中会使用专门的 IBM 实用工具;DB2 区域和必需的参数会被传递为该实用工具的输入。

在运行 COBOL-DB2 程序的过程中会跟随如下步骤:

  1. 当一个 COBOL-DB2 程序被编译时,将同时创建一个 DBRM(数据库请求模块)和加载模块。DBRM 包含 COBOL 程序的 SQL 语句,并且已检查其语法是否正确。

  2. DBRM 被绑定到 COBOL 将在其中运行的 DB2 区域(环境)。这可以使用 JCL 中的 IKJEFT01 实用工具来完成。

  3. 在绑定步骤之后,使用 IKJEFT01(再次)运行 COBOL-DB2 程序,并使用加载库和 DBRM 库作为 JCL 的输入。

//STEP001  EXEC PGM=IKJEFT01
//*
//STEPLIB  DD DSN=MYDATA.URMI.DBRMLIB,DISP=SHR
//*
//input files
//output files
//SYSPRINT DD SYSOUT=*
//SYSABOUT DD SYSOUT=*
//SYSDBOUT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//DISPLAY  DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN  DD *
    DSN SYSTEM(SSID)
    RUN PROGRAM(MYCOBB) PLAN(PLANNAME) PARM(parameters to cobol program) -
    LIB('MYDATA.URMI.LOADLIB')
    END
/*

在上述示例中,MYCOBB 是使用 IKJEFT01 运行的 COBOL-DB2 程序。请注意,程序名称、DB2 子系统 ID (SSID) 以及 DB2 计划名称会通过 SYSTSIN DD 语句传递。DBRM 库在 STEPLIB 中有所具体说明。

JCL - Utility Programs

IBM Dataset Utilities

实用程序是预先编写好的程序,被系统程序员和应用程序开发者广泛用于大型机,以满足日常需求、组织和维护数据。以下列出了一些实用程序及其功能:

Utility Name

Functionality

IEHMOVE

移动或拷贝顺序数据集。

IEHPROGM

删除和重命名数据集;编录或取消编录非 VSAM 的数据集。

IEHCOMPR

比较顺序数据集中数据。

IEBCOPY

复制、合并、压缩、备份或恢复 PDS。

IEFBR14

无操作实用程序。用于将控制返回给用户并终止。通常用于创建空数据集或删除现有数据集。例如,如果将数据集作为输入传递给 IEFBR14 程序,其中 DISP=(OLD,DELETE,DELETE),则在作业完成时删除该数据集。

IEBEDIT

用于复制 JCL 的选定部分。例如,如果 JCL 有 5 步,我们仅需要执行步 1 和 3,则可以编写包含要执行的实际 JCL 的数据集的 IEBEDIT JCL。在 IEBEDIT 的 SYSIN 中,我们可以指定 STEP1 和 STEP3 作为参数。执行此 JCL 时,将执行实际 JCL 的 STEP1 和 STEP3。

IDCAMS

创建、删除、重命名、编目、取消编目数据集(PDS 除外)。通常用于管理 VSAM 数据集。

要实现指定的功能,需要将这些实用程序与 JCL 中适当的 DD 语句一起使用。

DFSORT Overview

DFSORT 是 IBM 用于复制、排序或合并数据集的强大实用程序。SORTIN 和 SORTINnn DD 语句用于指定输入数据集。SORTOUT 和 OUTFIL 语句用于指定输出数据。

SYSIN DD 语句用于指定排序和合并条件。DFSORT 通常用于实现以下功能:

  1. 按文件中指定字段位置的顺序对输入文件进行 SORT。

  2. 根据指定条件在输入文件中 INCLUDE 或 OMIT 记录。

  3. 按文件中指定字段位置的顺序对 SORT MERGE 输入文件。

  4. 基于指定的 JOIN KEY(每个输入文件中字段)SORT JOIN 两个或更多个输入文件。

  5. 当需要对输入文件进行其他处理时,可以从 SORT 程序调用 USER EXIT 程序。例如,如果向输出文件添加页眉/页脚,则可以从 SORT 程序调用用户编写的 COBOL 程序来执行此功能。使用控制卡,可以将数据传递给 COBOL 程序。

  6. 另一方面,可以在 COBOL 程序中从内部调用 SORT,以便在处理之前按特定顺序排列输入文件。通常,由于性能问题而不建议对大文件这样做。

ICETOOL Overview

ICETOOL 是一款多用途 DFSORT 实用程序,用于对数据集执行各种操作。可以使用用户自定义的 DD 名称定义输入和输出数据集。文件操作在 TOOLIN DD 语句中指定。可以在用户自定义的“CTL”DD 语句中指定其他条件。

下面给出了 ICETOOL 的一些实用程序:

  1. ICETOOL 可以在一个或多个条件下实现 DFSORT 的所有功能。

  2. SPLICE 是 ICETOOL 的一项强大操作,类似于 SORT JOIN,但具有附加功能。它可以在指定字段比较两个或更多个文件,并创建匹配记录的文件、非匹配记录的文件等一个或多个输出文件。

  3. 可以将一个文件中的数据从特定位置 OVERLAY 到同一文件或不同文件中的另一个位置。

  4. 一个文件可以基于指定条件分割为 n 个文件。例如,包含员工姓名的文件可以分割成 26 个文件,每个文件包含以 A、B、C 等字母开头的姓名。

  5. 通过使用 ICETOOL 稍微探索一下,可以实现文件的不同组合操作。

SYNCSORT Overview

SYNCSORT 用于高性能地复制、合并或对数据集进行排序。它实现了对系统资源的最佳利用,并在 31 位和 64 位地址空间中进行高效的操作。

它可以在 DFSORT 的同等行中使用,可以实现相同的功能。它可以通过 JCL 或从用 COBOL、PL/1 或汇编语言编码的程序中调用。它还支持从 SYNCSORT 程序调用的用户出口程序。

在下一章中,将介绍使用这些实用程序的常用排序技巧。复杂的要求(需要在 COBOL/ASSEMBLER 中进行大量编程)可以使用上述实用程序通过简单的步骤来实现。

JCL - Basic Sort Tricks

下面说明了企业环境中可以使用实用程序实现的日常应用程序要求:

1. A file has 100 records. The first 10 records need to be written to output file.

//JSTEP020 EXEC PGM=ICETOOL
//TOOLMSG  DD SYSOUT=*
//DFSMSG   DD SYSOUT=*
//IN1      DD DSN=MYDATA.URMI.STOPAFT,DISP=SHR
//OUT1	   DD SYSOUT=*
//TOOLIN   DD *
  COPY FROM(IN1) TO(OUT1) USING(CTL1)
/*
//CTL1CNTL DD *
  OPTION STOPAFT=10
/*

STOPAFT 选项将在读取完第 10 条记录后停止读取输入文件并终止程序。因此,10 条记录将被写入输出。

2. Input file has one or more records for same employee number. Write unique records to output.

//STEP010  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=MYDATA.URMI.DUPIN,DISP=SHR
//SORTOUT  DD SYSOUT=*
//SYSIN    DD *
  SORT FIELDS=(1,15,ZD,A)
  SUM FIELDS=NONE
/*

SUM FIELDS=NONE 会删除 SORT FIELDS 中指定字段中的重复内容。在上述示例中,员工编号在字段位置 1,15。输出文件将包含以升序排序的唯一员工编号。

3. Overwrite input record content.

//JSTEP010 EXEC PGM=SORT
//SORTIN   DD DSN= MYDATA.URMI.SAMPLE.MAIN,DISP=SHR
//SORTOUT  DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//SYSIN    DD *
 OPTION COPY
  INREC OVERLAY=(47:1,6)
/*

在输入文件中,位置 1,6 中的内容被覆盖到位置 47,6,然后复制到输出文件中。INREC OVERLAY 操作用于在复制到输出之前重新写入输入文件中的数据。

4. Adding a sequence number to the output file.

//JSTEP010 EXEC PGM=SORT
//SORTIN   DD *
  data1
  data2
  data3
/*
//SORTOUT  DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//SYSIN    DD *
 OPTION COPY
 BUILD=(1:1,5,10:SEQNUM,4,ZD,START=1000,INCR=2)
/*

输出将为:

data1    1000
data2    1002
data3    1004

4 位序列号从 1000 开始并针对每条记录增加 2,添加到输出中的位置 10。

5. Adding Header/Trailer to output file.

//JSTEP010 EXEC PGM=SORT
//SORTIN   DD *
  data1
  data2
  data3
/*
//SORTOUT  DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//SYSIN    DD *
 SORT FIELDS=COPY
  OUTFIL REMOVECC,
  HEADER1=(1:C'HDR',10:X'020110131C'),
  TRAILER1=(1:C'TRL',TOT=(10,9,PD,TO=PD,LENGTH=9))
/*

输出将为:

HDR       20110131
data1
data2
data3
TRL       000000003

TOT 计算输入文件中的记录数。HDR 和 TRL 作为标识符添加到页眉/尾部,它是由用户定义的,并且可以根据用户的需要进行自定义。

6. Conditional Processing

//JSTEP010 EXEC PGM=SORT
//SORTIN   DD *
  data1select
  data2
  data3select
/*
//SORTOUT  DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//SYSIN    DD *
  INREC  IFTHEN=(WHEN=(6,1,CH,NE,C' '),BUILD=(1:1,15),
         IFTHEN=(WHEN=(6,1,CH,EQ,C' '),BUILD=(1:1,5,7:C'EMPTY    ')
  OPTION COPY
/*

输出将为:

data1select
data2 EMPTY
data3select

基于文件的第 6 个位置,输出文件 BUILD 会有所不同。如果第 6 个位置为空格,那么文本“EMPTY”将附加到输入记录。否则,输入记录将按原样写入输出。

7. Backing up a file

//JSTEP001 EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
//SYSOUT   DD SYSOUT=*
//SORTOUT  DD DUMMY
//SYSUT1   DD DSN=MYDATA.URMI.ORIG,DISP=SHR
//SYSUT2   DD DSN=MYDATA.URMI.BACKUP,DISP=(NEW,CATLG,DELETE),
//             DCB=*.SYSUT1,SPACE=(CYL,(50,1),RLSE)

IEBGENER 将 SYSUT1 中的文件复制到 SYSUT2 中的文件。请注意,SYSUT2 中的文件采用的 DCB 与上述示例中的 SYSUT1 相同。

8. File Comparison

//STEP010  EXEC PGM=SORT
//MAIN     DD *
  1000
  1001
  1003
  1005
//LOOKUP   DD *
  1000
  1002
  1003
//MATCH    DD DSN=MYDATA.URMI.SAMPLE.MATCH,DISP=OLD
//NOMATCH1 DD DSN=MYDATA.URMI.SAMPLE.NOMATCH1,DISP=OLD
//NOMATCH2 DD DSN=MYDATA.URMI.SAMPLE.NOMATCH2,DISP=OLD
//SYSOUT   DD SYSOUT=*
//SYSIN    DD *
  JOINKEYS F1=MAIN,FIELDS=(1,4,A)
  JOINKEYS F2=LOOKUP,FIELDS=(1,4,A)
  JOIN UNPAIRED,F1,F2
  REFORMAT FIELDS=(?,F1:1,4,F2:1,4)
  OPTION COPY
  OUTFIL FNAMES=MATCH,INCLUDE=(1,1,CH,EQ,C'B'),BUILD=(1:2,4)
  OUTFIL FNAMES=NOMATCH1,INCLUDE=(1,1,CH,EQ,C'1'),BUILD=(1:2,4)
  OUTFIL FNAMES=NOMATCH2,INCLUDE=(1,1,CH,EQ,C'2'),BUILD=(1:2,4)
/*
  1. JOINKEYS 指定在该字段上比较两个文件。

  2. REFORMAT FIELDS=? 在输出 BUILD 的第一位放入“B”(匹配记录)、“1”(文件 1 中存在但文件 2 中不存在)或“2”(文件 2 中存在但文件 1 中不存在)。

  3. JOIN UNPAIRED 在两个文件上执行全外部连接。

输出将为:

MATCH File
1000
1003

NOMATCH1 File
1001
1005

NOMATCH2 File
1002

使用 ICETOOL 也可以实现相同的功能。