Appendix B: JCL Quick Reference
JCL is the language of the mainframe batch infrastructure. Every COBOL program that runs in batch does so because JCL told the system what to run, where to find it, what files to allocate, and what to do when something goes wrong. This reference covers what you need to write, read, and debug JCL in a production environment.
All JCL statements begin in column 1 with //. Comments begin with //*. Continuation requires breaking after a comma, coding // in columns 1-2 of the next line, and resuming the parameter in column 16 (or after at least one space following //).
JOB Statement
The JOB statement identifies the job to JES and specifies job-level parameters.
//JOBNAME JOB (ACCT,INFO),'PROGRAMMER NAME',
// CLASS=A,
// MSGCLASS=X,
// MSGLEVEL=(1,1),
// NOTIFY=&SYSUID,
// REGION=0M,
// TIME=1440,
// TYPRUN=SCAN
Key JOB Parameters
| Parameter | Purpose | Common Values |
|---|---|---|
CLASS |
Job class (determines initiator) | A-Z, 0-9; installation-defined |
MSGCLASS |
Output class for job log | X (held), A (print), installation-defined |
MSGLEVEL |
Job log detail | (1,1) = all JCL + all messages (use this for debugging) |
NOTIFY |
TSO user to notify on completion | &SYSUID (yourself) |
REGION |
Memory limit | 0M (unlimited, up to installation max) |
TIME |
CPU time limit | 1440 (no limit), (mm,ss), or NOLIMIT |
TYPRUN |
Special processing | SCAN (syntax check only), HOLD, COPY |
RESTART |
Restart from a step | stepname or procstep.stepname |
COND |
Job-level condition code test | Deprecated; use IF/THEN/ELSE |
SCHENV |
WLM scheduling environment | Installation-defined |
REGION=0M requests the maximum region size the installation allows. In practice, most COBOL batch jobs need far less. Some shops set job-class defaults and prohibit REGION=0M in production.
TYPRUN=SCAN is your best friend when writing new JCL. It checks syntax without actually running anything. Always scan first.
EXEC Statement
The EXEC statement identifies a program or procedure to execute within a step.
//* Execute a program directly
//STEP01 EXEC PGM=MYPROG,PARM='INPUT=PROD'
//* Execute a cataloged procedure
//STEP02 EXEC PROC=MYPROC
//STEP02 EXEC MYPROC (PROC= is optional)
//* With overrides
//STEP03 EXEC PGM=MYPROG,
// REGION=256M,
// TIME=30,
// COND=(4,LT)
Key EXEC Parameters
| Parameter | Purpose | Notes |
|---|---|---|
PGM |
Program name | Load module from STEPLIB or link list |
PROC |
Procedure name | From JCLLIB or system proclib |
PARM |
Parameter string passed to program | Max 100 characters; passed via PARM on EXEC |
REGION |
Step memory limit | Overrides JOB-level REGION |
TIME |
Step CPU time limit | Overrides JOB-level TIME |
COND |
Condition code test for step bypass | Deprecated; use IF/THEN/ELSE |
ACCT |
Step-level accounting | Installation-defined |
PARM encoding: The system passes the PARM string to the program as a halfword length prefix followed by the character data. In COBOL, the Linkage Section receives it:
LINKAGE SECTION.
01 LS-PARM.
05 LS-PARM-LENGTH PIC S9(04) COMP.
05 LS-PARM-DATA PIC X(100).
PROCEDURE DIVISION USING LS-PARM.
DD Statement
The DD (Data Definition) statement defines data sets and I/O resources for a step.
//* Existing sequential data set
//INPUTDD DD DSN=PROD.DAILY.EXTRACT,
// DISP=SHR
//* New sequential data set
//OUTPUTDD DD DSN=PROD.DAILY.REPORT,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(50,10),RLSE),
// DCB=(RECFM=FB,LRECL=133,BLKSIZE=0),
// UNIT=SYSDA
//* Temporary data set
//TEMPDD DD DSN=&&TEMPFILE,
// DISP=(NEW,PASS),
// SPACE=(TRK,(100,50)),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
//* In-stream data
//SYSIN DD *
SELECT FIELDS=(1,10,CH,A)
/*
//* Concatenation
//INPUT DD DSN=PROD.FILE.PART1,DISP=SHR
// DD DSN=PROD.FILE.PART2,DISP=SHR
// DD DSN=PROD.FILE.PART3,DISP=SHR
//* SYSOUT (print/spool)
//SYSPRINT DD SYSOUT=*
//* DUMMY (no I/O)
//OPTIONAL DD DUMMY
DSN (Data Set Name)
- Maximum 44 characters
- Qualifiers separated by periods, each max 8 characters
&&namecreates a temporary data set (exists only for job duration)*.stepname.ddnamerefers back to a data set from a previous step
//* Back-reference to a data set from a previous step
//INPUTDD DD DSN=*.STEP01.OUTPUTDD,DISP=SHR
DISP (Disposition)
Format: DISP=(status,normal-end,abnormal-end)
Status (before step):
| Value | Meaning |
|---|---|
NEW |
Create new data set |
OLD |
Existing, exclusive access |
SHR |
Existing, shared access |
MOD |
Existing (extend) or new (create) |
Normal termination disposition:
| Value | Meaning |
|---|---|
DELETE |
Delete the data set |
KEEP |
Keep but don't catalog |
CATLG |
Keep and catalog |
PASS |
Pass to a subsequent step |
UNCATLG |
Uncatalog but keep on volume |
Abnormal termination disposition:
Same values as normal. Defaults: if you code DISP=SHR, the default is (SHR,KEEP,KEEP). If you code DISP=(NEW,CATLG), the abnormal default is the same as normal — (NEW,CATLG,CATLG), which often is not what you want. For new data sets, code the abnormal disposition explicitly:
//OUTPUT DD DSN=PROD.FILE,DISP=(NEW,CATLG,DELETE)
This ensures the data set is cleaned up if the step abends.
SPACE
Format: SPACE=(unit,(primary,secondary,directory),RLSE,,type)
| Unit | Meaning |
|---|---|
TRK |
Tracks (~56 KB per track on 3390) |
CYL |
Cylinders (~840 KB per cylinder on 3390) |
nnn |
Average block size in bytes |
//* 50 cylinders primary, 10 secondary, release unused
SPACE=(CYL,(50,10),RLSE)
//* PDS with 20 directory blocks
SPACE=(TRK,(200,50,20))
RLSE releases unused space at CLOSE. Always code it for output data sets — without it, you waste DASD.
Secondary allocation can occur up to 15 times per volume. If you exceed that, the job abends with Sx37 (out of space). Size your primary allocation generously.
DCB (Data Control Block)
DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
| Parameter | Values | Meaning |
|---|---|---|
RECFM |
F, FB, V, VB, FBA, VBA, U | Record format. F=fixed, V=variable, B=blocked, A=ASA control char, U=undefined |
LRECL |
1-32760 | Logical record length |
BLKSIZE |
0 or explicit | Block size. 0 = system-determined (optimal). Always use 0 for new data sets. |
DSORG |
PS, PO, DA | Data set organization (usually not needed) |
BLKSIZE=0 lets SMS (Storage Management Subsystem) or the system calculate the optimal block size. This is almost always what you want. Hard-coding BLKSIZE is a legacy practice from the days of physical tape handling.
UNIT and VOL
//OUTPUT DD DSN=PROD.FILE,DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(100,20),RLSE),
// UNIT=SYSDA,
// VOL=SER=PROD01
UNIT=SYSDA is the generic DASD unit. UNIT=TAPE for tape. Most SMS-managed environments don't require explicit UNIT or VOL — SMS assigns them based on data class and storage group. Only code them when you have a specific reason.
JCLLIB and PROCs
JCLLIB
//MYJOB JOB ...
// JCLLIB ORDER=(MY.PROC.LIB,
// SHARED.PROC.LIB)
JCLLIB tells JES where to find cataloged procedures and include members. It must appear immediately after the JOB statement, before any EXEC. Multiple libraries are searched in order.
Cataloged Procedures
A PROC is a pre-written set of JCL steps stored in a procedure library.
//* In the proclib:
//COBCL PROC SRCLIB='DEV.SOURCE.LIB',
// MEMBER='MYPROG'
//COB EXEC PGM=IGYCRCTL,PARM='OPT(2),LIST'
//STEPLIB DD DSN=IGY.V6R4M0.SIGYCOMP,DISP=SHR
//SYSIN DD DSN=&SRCLIB(&MEMBER),DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSLIN DD DSN=&&OBJMOD,DISP=(MOD,PASS),
// SPACE=(TRK,(10,5)),UNIT=SYSDA
//LKED EXEC PGM=IEWL,PARM='LIST,MAP',
// COND=(8,LT,COB)
//SYSLIN DD DSN=&&OBJMOD,DISP=(OLD,DELETE)
//SYSLMOD DD DSN=MY.LOAD.LIB(&MEMBER),DISP=SHR
//SYSPRINT DD SYSOUT=*
// PEND
Invoking and Overriding PROCs
//* Invoke with symbolic parameter overrides
//STEP01 EXEC COBCL,SRCLIB='PROD.SOURCE.LIB',
// MEMBER='BATCHPGM'
//* Override a DD within a proc step
//COB.SYSIN DD DSN=MY.SPECIAL.SOURCE(MYPROG),DISP=SHR
//* Add a DD to a proc step
//LKED.EXTRADD DD DSN=MY.EXTRA.OBJ,DISP=SHR
The syntax for overriding is procstep.ddname. This is the single most confusing aspect of JCL for newcomers. The procstep name is the step name inside the proc, not the step name in your JCL.
IF/THEN/ELSE/ENDIF
//* Skip step if previous step had RC > 0
// IF (STEP01.RC = 0) THEN
//STEP02 EXEC PGM=NEXTPROG
//INPUT DD DSN=PROD.FILE,DISP=SHR
// ENDIF
//* Complex condition
// IF (STEP01.RC <= 4 AND
// STEP02.RC = 0) THEN
//STEP03 EXEC PGM=FINALPGM
// ELSE
//ERRSTEP EXEC PGM=ERRHANDL
// ENDIF
//* Test abend
// IF (STEP01.ABEND) THEN
//RECOVER EXEC PGM=RECOVERY
// ENDIF
//* Test for specific abend code
// IF (STEP01.ABENDCC = S0C7) THEN
//FIXDATA EXEC PGM=DATAFIX
// ENDIF
Operators: =, != (or <> or ^=), >, <, >=, <=, AND, OR, NOT
Testable conditions: stepname.RC, stepname.ABEND, stepname.ABENDCC, stepname.RUN, stepname.procstep.RC
IF/THEN/ELSE completely replaces the old COND parameter. There is no reason to use COND in new JCL. COND tests are backwards (the condition is when to skip), and they confuse everyone. Use IF/THEN/ELSE.
SET and Symbolic Parameters
//* SET statement for symbolic parameters
// SET ENV=PROD
// SET HLQ=PROD.DAILY
//STEP01 EXEC PGM=MYPROG
//INPUT DD DSN=&HLQ..EXTRACT,DISP=SHR
//OUTPUT DD DSN=&HLQ..REPORT,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(50,10),RLSE)
Note the double period in &HLQ..EXTRACT — the first period terminates the symbolic, the second is the DSN qualifier separator. This is a common source of JCL errors.
INCLUDE and JCLLIB
// JCLLIB ORDER=(MY.JCL.LIB)
// INCLUDE MEMBER=STDALLOC
INCLUDE pulls in a member from the JCLLIB, similar to COBOL's COPY. Use it for standard DD allocations that appear across many jobs.
Common Utility Programs
IDCAMS (Access Method Services)
The Swiss army knife of VSAM and catalog management.
//* Define a VSAM KSDS
//DEFCLUST EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEFINE CLUSTER( -
NAME(PROD.CUSTOMER.KSDS) -
INDEXED -
RECORDSIZE(200 500) -
KEYS(10 0) -
SHAREOPTIONS(2 3) -
CYLINDERS(100 20)) -
DATA(NAME(PROD.CUSTOMER.KSDS.DATA)) -
INDEX(NAME(PROD.CUSTOMER.KSDS.INDEX))
/*
//* Delete a data set (ignore "not found" errors)
//DELETE EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE PROD.OLD.FILE PURGE
SET MAXCC = 0
/*
//* REPRO (copy data into VSAM)
//REPRO EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INDD DD DSN=PROD.SEQ.FILE,DISP=SHR
//OUTDD DD DSN=PROD.CUSTOMER.KSDS,DISP=SHR
//SYSIN DD *
REPRO INFILE(INDD) OUTFILE(OUTDD)
/*
//* LISTCAT
//LISTCAT EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ENTRIES(PROD.CUSTOMER.KSDS) ALL
/*
//* VERIFY (reset VSAM after abend)
//VERIFY EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//MYFILE DD DSN=PROD.CUSTOMER.KSDS,DISP=SHR
//SYSIN DD *
VERIFY FILE(MYFILE)
/*
SET MAXCC = 0 after DELETE is a standard pattern: it prevents a "data set not found" condition (which returns RC=8) from failing the job. This makes the DELETE idempotent.
IEBGENER (Sequential Copy)
//COPY EXEC PGM=IEBGENER
//SYSUT1 DD DSN=INPUT.FILE,DISP=SHR
//SYSUT2 DD DSN=OUTPUT.FILE,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(10,5),RLSE),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
//SYSPRINT DD SYSOUT=*
//SYSIN DD DUMMY
SYSIN DD DUMMY means a straight copy with no reformatting. IEBGENER is the simplest way to copy a sequential data set. For anything more complex, use DFSORT or ICETOOL.
IEFBR14 (Do Nothing)
//* Create or delete data sets without running a program
//ALLOC EXEC PGM=IEFBR14
//NEWFILE DD DSN=PROD.NEW.FILE,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(50,10),RLSE),
// DCB=(RECFM=FB,LRECL=200,BLKSIZE=0)
//OLDFILE DD DSN=PROD.OLD.FILE,
// DISP=(OLD,DELETE,DELETE)
IEFBR14 is a one-instruction program (BR 14 = return). It exists solely to give JCL a program to execute so that DD statements are processed. You use it to allocate, delete, or catalog data sets without running real code.
DFSORT
//SORT EXEC PGM=SORT
//SORTIN DD DSN=INPUT.FILE,DISP=SHR
//SORTOUT DD DSN=OUTPUT.FILE,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(50,10),RLSE)
//SYSOUT DD SYSOUT=*
//SYSIN DD *
SORT FIELDS=(1,10,CH,A,11,5,ZD,D)
INCLUDE COND=(20,2,CH,EQ,C'NY')
OUTREC FIELDS=(1,10,21,30,80:X)
OUTFIL REMOVECC,
HEADER1=('CUSTOMER REPORT',5X,DATE=(4MD/)),
TRAILER1=('TOTAL RECORDS: ',COUNT)
/*
DFSORT control statements:
| Statement | Purpose |
|---|---|
SORT FIELDS |
Sort keys: (position,length,format,order) |
MERGE FIELDS |
Merge pre-sorted inputs |
INCLUDE COND |
Include records matching condition |
OMIT COND |
Exclude records matching condition |
INREC |
Reformat records before sort |
OUTREC |
Reformat records after sort |
OUTFIL |
Multiple output files, reporting |
SUM FIELDS |
Summarize (eliminate duplicates, sum numeric fields) |
Format types: CH (character), ZD (zoned decimal), PD (packed decimal), BI (binary), FI (fixed-point integer), AC (ASCII character)
ICETOOL
//TOOL EXEC PGM=ICETOOL
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//INPUT DD DSN=PROD.TRANS.FILE,DISP=SHR
//REPORT DD SYSOUT=*
//SUBSET DD DSN=PROD.SUBSET.FILE,
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(10,5),RLSE)
//TOOLIN DD *
COPY FROM(INPUT) TO(SUBSET) USING(CTL1)
DISPLAY FROM(INPUT) LIST(REPORT) -
TITLE('Transaction Summary') -
HEADER('Account') ON(1,10,CH) -
HEADER('Amount') ON(15,9,ZD,A2) -
HEADER('Count') ON(VALCNT) -
BLANK -
HEADER('Total') ON(15,9,ZD,A2,TOTAL)
//CTL1CNTL DD *
INCLUDE COND=(25,8,CH,EQ,C'20260317')
/*
ICETOOL wraps DFSORT with higher-level operations: COPY, SORT, SELECT, DISPLAY, COUNT, STATS, RANGE, VERIFY. The DISPLAY operation is particularly powerful for ad-hoc reporting without writing a program.
JES2 JECL (Job Entry Control Language)
/*JOBPARM SYSAFF=SY1,LINES=9999
/*ROUTE PRINT R001
/*ROUTE XEQ NODE1
/*PRIORITY 6
/*OUTPUT FORMS=STD,COPIES=2
| Statement | Purpose |
|---|---|
/*JOBPARM |
Job parameters (system affinity, output limits) |
/*ROUTE PRINT |
Route printed output |
/*ROUTE XEQ |
Route job execution to a specific node |
/*PRIORITY |
Scheduling priority (0-15) |
/*OUTPUT |
Output processing options |
/*XMIT |
Transmit job to another node |
SYSAFF=SY1 forces the job to run on system SY1 in a sysplex. Use it when a job requires resources available only on a specific LPAR. Avoid it when possible — it reduces workload balancing flexibility.
OUTPUT JCL Statement
//MYOUT OUTPUT DEST=RMT001,
// COPIES=3,
// FORMS=INVOICE,
// CLASS=A,
// DEFAULT=YES
The OUTPUT statement provides finer control over printed/spooled output. DEFAULT=YES applies these options to all SYSOUT DDs in the step that don't specify their own output descriptor.
GDG (Generation Data Groups)
//* Define a GDG base (one-time setup via IDCAMS)
//DEFGDG EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEFINE GDG(NAME(PROD.DAILY.EXTRACT) -
LIMIT(30) -
NOEMPTY -
SCRATCH)
/*
//* Write to a new generation
//NEWGEN DD DSN=PROD.DAILY.EXTRACT(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(100,20),RLSE),
// DCB=(RECFM=FB,LRECL=200,BLKSIZE=0)
//* Read the current (most recent) generation
//CURGEN DD DSN=PROD.DAILY.EXTRACT(0),DISP=SHR
//* Read the previous generation
//PREVGEN DD DSN=PROD.DAILY.EXTRACT(-1),DISP=SHR
GDGs provide automatic versioning. (+1) creates the next generation, (0) is the current, (-1) is the one before. The LIMIT controls how many generations are kept. SCRATCH means the oldest generation's DASD space is released when it rolls off.
Common DD Names
These DD names are conventions (some enforced by specific programs):
| DD Name | Used By | Purpose |
|---|---|---|
STEPLIB |
Loader | Program search library (step-level) |
JOBLIB |
Loader | Program search library (job-level) |
SYSPRINT |
Most programs | Primary print output |
SYSOUT |
DFSORT | Sort messages |
SYSIN |
Many utilities | Control statements |
SYSUT1 |
IEBGENER | Input |
SYSUT2 |
IEBGENER | Output |
SYSUDUMP |
System | Formatted dump on abend |
SYSABEND |
System | Formatted dump (more detail) |
CEEDUMP |
LE | Language Environment dump |
SORTIN |
DFSORT | Sort input |
SORTOUT |
DFSORT | Sort output |
SORTWKnn |
DFSORT | Sort work files |
SYSDBOUT |
Debug Tool | Debug output |
SYSDEBUG |
Compiler | Debug side file |
Return Code Conventions
| RC | Meaning |
|---|---|
| 0 | Successful, no issues |
| 4 | Warning (completed with minor issues) |
| 8 | Error (significant issues but some processing completed) |
| 12 | Severe error (minimal or no useful processing) |
| 16 | Critical error (no processing) |
These are conventions, not standards. Your programs should follow them, and your JCL IF/THEN/ELSE tests should be based on them. A common pattern:
// IF (STEP01.RC > 4) THEN
//NOTIFY EXEC PGM=SENDMAIL,PARM='STEP01 FAILED'
// ENDIF
Debugging JCL Checklist
When a job fails, check in this order:
- JESMSGLG — System messages, including security (RACF) failures
- JESJCL — Expanded JCL (with all symbolics resolved and procs expanded)
- JESYSMSG — Allocation messages (look for IEF244I, IEF272I, IEF285I)
- Step condition codes — In JESMSGLG, look for IEF142I messages
- SYSPRINT — Program-level messages
- SYSOUT — Additional program output
- CEEDUMP — Language Environment dump (if LE abend)
- SYSUDUMP/SYSABEND — System dump (if system abend)
Common JCL errors:
| Error | Message | Cause |
|---|---|---|
| JCL ERROR | IEFC621I | Syntax error — check continuation, spelling, commas |
| NOT FOUND | IEF212I | Data set does not exist or is not cataloged |
| NOT CATLGD 2 | IGD17101I | Data set already exists (duplicate catalog entry) |
| ABEND S913 | — | RACF security violation |
| ABEND S806 | — | Program not found in STEPLIB/JOBLIB/link list |
| ABEND Sx37 | — | Out of space |
JCL Templates
Standard Compile-Link-Go
//COMPILE JOB (ACCT),'COMPILE',CLASS=A,
// MSGCLASS=X,MSGLEVEL=(1,1),
// NOTIFY=&SYSUID
// JCLLIB ORDER=(SYS1.PROCLIB)
//*
//COB EXEC PGM=IGYCRCTL,
// PARM='OPT(2),FASTSRT,RENT,OFFSET,LIB'
//STEPLIB DD DSN=IGY.V6R4M0.SIGYCOMP,DISP=SHR
//SYSIN DD DSN=MY.SOURCE.LIB(MYPROG),DISP=SHR
//SYSLIB DD DSN=MY.COPY.LIB,DISP=SHR
// DD DSN=SHARED.COPY.LIB,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSLIN DD DSN=&&OBJMOD,DISP=(MOD,PASS),
// SPACE=(CYL,(1,1)),UNIT=SYSDA
//SYSUT1 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//SYSUT2 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//SYSUT3 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//SYSUT4 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//SYSUT5 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//SYSUT6 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//SYSUT7 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//*
//LKED EXEC PGM=IEWL,PARM='LIST,MAP,RENT',
// COND=(8,LT,COB)
//SYSLIN DD DSN=&&OBJMOD,DISP=(OLD,DELETE)
//SYSLMOD DD DSN=MY.LOAD.LIB(MYPROG),DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD SPACE=(CYL,(1,1)),UNIT=SYSDA
//*
//GO EXEC PGM=*.LKED.SYSLMOD,
// COND=(8,LT)
//STEPLIB DD DSN=MY.LOAD.LIB,DISP=SHR
//SYSPRINT DD SYSOUT=*
//INPUT DD DSN=MY.TEST.INPUT,DISP=SHR
//OUTPUT DD SYSOUT=*
Standard Batch Run
//BATCHRUN JOB (ACCT),'DAILY BATCH',CLASS=A,
// MSGCLASS=X,MSGLEVEL=(1,1),
// NOTIFY=&SYSUID,
// REGION=0M
//*
//STEP01 EXEC PGM=BATCHPGM
//STEPLIB DD DSN=PROD.LOAD.LIB,DISP=SHR
//INPUT DD DSN=PROD.DAILY.EXTRACT(0),DISP=SHR
//OUTPUT DD DSN=PROD.DAILY.REPORT(+1),
// DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(100,20),RLSE),
// DCB=(RECFM=FB,LRECL=200,BLKSIZE=0)
//SYSPRINT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//CEEDUMP DD SYSOUT=*
Always allocate SYSUDUMP (or SYSABEND) and CEEDUMP in production JCL. When a program abends at 2 AM, the dump is the difference between a 10-minute fix and a 2-hour blind investigation.