LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1519 min read

JCL: The EXEC Statement

Learn how the EXEC statement defines a job step: running a program directly with PGM=, calling a reusable procedure with PROC=, and passing parameters into either.

Introduction

If the JOB statement establishes who a job belongs to, the EXEC statement is where a job actually starts doing something. Every EXEC statement defines one step, and a step is where z/OS is told exactly which program should run. This lesson covers the two ways to specify that — running a program directly, or invoking a reusable procedure — along with how to pass parameters and chain multiple steps together.

What a Step Is

A step is one execution of a single program within a job. A job can consist of a single step or dozens of them, executed one after another, each doing a distinct piece of work — one step might sort a file, the next might run a COBOL program against the sorted output, and a third might produce a summary report. Each step gets its own EXEC statement and its own set of DD statements describing the data that specific step needs.

Job vs. Step

A job is the whole unit of work described by one JOB statement. A step is one program execution inside that job, described by one EXEC statement. A single job with five EXEC statements has five steps, all sharing the same job-level identity and accounting established on the JOB card.

PGM=: Running a Program Directly

The simplest form of an EXEC statement names a specific program to run using the PGM= parameter. That program must exist as an executable load module in a library z/OS can search (typically a system library or one explicitly added to the search order through a JOBLIB or STEPLIB DD statement).

A step that runs a program directly
//STEP010 EXEC PGM=SORT

This is straightforward: z/OS locates the load module named SORT and executes it as this step, using whatever DD statements follow to supply its input and output data and its control statements.

PROC=: Calling a Procedure

The alternative to PGM= is invoking a procedure (PROC) — a pre-written, reusable block of JCL, usually containing one or more EXEC and DD statements already set up for a common task. Instead of retyping the same JCL every time a shop needs to, say, compile a COBOL program, that logic is written once as a procedure and simply invoked by name.

A step that invokes a procedure
//STEP010 EXEC COBCOMP

Here, COBCOMP is not a program name passed via PGM= — it is the name of a procedure (cataloged in a procedure library, or coded in-stream earlier in the same job) that itself contains one or more steps with their own PGM= references and DD statements. The next lesson in this course, on JCL procedures, covers exactly how PROCs are built, cataloged, and overridden; for now, the important distinction is simply PGM= runs one specific program, while a bare procedure name invokes a whole pre-packaged block of JCL.

How to Tell Them Apart at a Glance

If you see EXEC PGM=something, that step runs exactly one named program. If you see EXEC something with no PGM= keyword at all, that "something" is a procedure name, and the actual program(s) it runs are defined inside the procedure itself, not on this line.

Passing Parameters with PARM

Many programs accept runtime parameters — small pieces of control information that change their behavior without requiring different JCL or a different compiled program. The PARM keyword on an EXEC statement passes that information directly into the program at execution time, where the program reads it (for a COBOL program, typically through the DATA DIVISION's LINKAGE SECTION, connected via the PROCEDURE DIVISION USING clause).

Passing a runtime parameter
//STEP010 EXEC PGM=RPTGEN,PARM='MONTH=06,YEAR=2026'
What this achieves

Click Run to see what this code prints.

Multiple Steps in One Job

Real batch jobs frequently chain several steps together, where the output dataset of one step becomes the input dataset of the next. This lets a single job perform a whole pipeline of work — sort, then process, then report — as one coordinated, trackable unit, rather than several separate jobs that would need to be manually sequenced.

A three-step pipeline (conceptual)
//STEP010 EXEC PGM=SORT (sort raw transactions)
//STEP020 EXEC PGM=TRANPROC (process sorted transactions)
//STEP030 EXEC PGM=RPTGEN (generate a summary report)

Controlling Whether a Step Runs: COND

By default, z/OS runs every step in a job in sequence regardless of whether earlier steps succeeded, unless a step fails so severely (an abend) that the job is flushed. Often, though, later steps only make sense if earlier ones succeeded — there is no point generating a report from data a failed sort step never produced. The COND parameter lets a step test the condition code (return code) of prior steps and be skipped if a specified condition is met.

Skipping a step if an earlier one failed
//STEP030 EXEC PGM=RPTGEN,COND=(4,LT,STEP010)
Reading it

Click Run to see what this code prints.

A Complete Multi-Step Example

A job with two steps and parameters
//RPTJ020 JOB (ACCT77),'M PATEL',CLASS=B,MSGCLASS=X,NOTIFY=&SYSUID
//STEP010 EXEC PGM=SORT
//SORTIN DD DSN=PROD.TRANS.RAW,DISP=SHR
//SORTOUT DD DSN=PROD.TRANS.SORTED,DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(10,5)),DCB=(RECFM=FB,LRECL=100)
//SYSIN DD *
SORT FIELDS=(1,10,CH,A)
/*
//STEP020 EXEC PGM=RPTGEN,PARM='MONTH=06,YEAR=2026'
//RPTIN DD DSN=PROD.TRANS.SORTED,DISP=SHR
//RPTOUT DD SYSOUT=*
Reading it

Click Run to see what this code prints.

Common Mistakes

Avoid These Mistakes
  • Confusing PGM= (runs one named program) with a bare procedure name (invokes a whole pre-written block of JCL) — they look similar but behave very differently.
  • Forgetting that PARM values with special characters or embedded commas usually need to be enclosed in quotes.
  • Misreading COND logic — remember it specifies the condition under which a step is skipped, not the condition under which it runs, which trips up even experienced JCL writers.
  • Reusing the same stepname twice within one job, which is not permitted and will cause a JCL error.

Best Practices

  • Give steps clear, sequential names (STEP010, STEP020) so the flow of the job is obvious at a glance.
  • Prefer IF/THEN/ELSE JCL over COND for anything beyond a single simple check — it reads far more naturally.
  • Keep each step focused on one clear task (sort, process, report) rather than combining unrelated work into a single step.
  • Document PARM values with a nearby comment when their meaning is not self-evident from the text alone.

Frequently Asked Questions

PGM= names one specific executable program to run in this step. Invoking a procedure by name (with or without the optional PROC= keyword) instead runs a pre-written block of JCL, which typically contains its own EXEC statements naming the actual programs to run.

There is a practical installation-defined limit (often in the hundreds), but for typical production and learning purposes, think of it as "as many as the work logically requires" — most jobs have anywhere from one to a few dozen steps.

It is a numeric status the program sets when it finishes, by convention 0 for full success, with higher values indicating warnings or errors (this convention varies somewhat by program, but 0 as success is nearly universal). COND and IF/THEN/ELSE JCL logic act on these return codes.

Only if the program is written to read it. In COBOL, this means the program's PROCEDURE DIVISION includes a USING clause connected to a LINKAGE SECTION field. A program that does not expect PARM data will simply ignore it if none is coded, or may fail if PARM data is passed unexpectedly.

Key Takeaways

  • The EXEC statement defines one step; a job can contain many steps executed in sequence.
  • PGM= runs a single named program directly; invoking a procedure by name runs a reusable, pre-packaged block of JCL instead.
  • PARM passes runtime control information into a program without requiring separate JCL or code per scenario.
  • COND (and its more readable successor, IF/THEN/ELSE JCL) lets later steps be skipped based on earlier steps' return codes.
  • Multi-step jobs let related work — sort, process, report — run as one coordinated, trackable unit.

Summary

The EXEC statement is where a JCL job stream turns into actual work: naming a program directly, invoking a reusable procedure, and optionally passing parameters or conditions that shape exactly how and whether each step runs. The next lesson completes the core JCL trio by covering the DD statement — how a program's internal file references actually get connected to real datasets sitting on disk or tape.

Next Lesson →

JCL: The DD Statement