Using structured conditional logic in JCL for flexible job flows
While the COND parameter provides a way to conditionally execute job steps, JCL also offers a more structured and readable approach with IF/THEN/ELSE/ENDIF statements. These statements allow for more complex conditional logic and provide a clearer representation of the intended flow.
IF/THEN/ELSE statements were introduced to JCL to provide enhanced conditional processing capabilities with more intuitive syntax. This tutorial covers how to use these statements to create sophisticated conditional job flows.
The basic structure of IF/THEN/ELSE in JCL is as follows:
Basic Syntax:
12345// IF condition THEN //stepname EXEC PGM=program1 // ELSE //stepname EXEC PGM=program2 // ENDIF
Key points about the IF/THEN/ELSE syntax:
Unlike the COND parameter, the IF statement logic is intuitive - the THEN clause is executed if the condition is true. This makes IF statements much easier to read and understand compared to the "bypass if true" logic of COND parameters.
IF statements evaluate condition expressions that typically compare return codes. The condition must be enclosed in parentheses.
GT - Greater Than
IF (STEP1.RC GT 4)
GE - Greater than or Equal
IF (STEP1.RC GE 8)
LT - Less Than
IF (STEP1.RC LT 8)
LE - Less than or Equal
IF (STEP1.RC LE 4)
EQ or = - Equal
IF (STEP1.RC = 0)
NE - Not Equal
IF (STEP1.RC NE 0)
12345// IF (STEP1.RC = 0) THEN // IF (RC = 0) THEN // IF (MAXRC < 8) THEN // IF (COMPILE.RC = 0) THEN // IF (ABEND = TRUE) THEN
JCL IF statements support logical operators to combine multiple conditions:
Both conditions must be true
1IF ((STEP1.RC = 0) AND (STEP2.RC < 8)) THEN
At least one condition must be true
1IF ((STEP1.RC = 0) OR (STEP2.RC = 0)) THEN
When combining multiple logical operators, use parentheses to indicate precedence:
1IF ((STEP1.RC = 0) AND ((STEP2.RC = 0) OR (STEP3.RC = 0))) THEN
JCL evaluates the entire logical expression, even if the result could be determined before completing the evaluation (unlike some programming languages that use short-circuit evaluation). This means all steps referenced in the condition must have executed previously in the job.
JCL supports nesting of IF/THEN/ELSE structures, allowing for more complex decision trees:
123456789// IF (STEP1.RC = 0) THEN //STEPA EXEC PGM=PROGRAMA // ELSE // IF (STEP1.RC = 4) THEN //STEPB EXEC PGM=PROGRAMB // ELSE //STEPC EXEC PGM=PROGRAMC // ENDIF // ENDIF
In this example, if STEP1 has a return code of 0, PROGRAMA executes. If it's 4, PROGRAMB executes. For any other return code, PROGRAMC executes.
A more flexible version of the compile-link-execute pattern using IF/THEN/ELSE:
123456789101112131415161718192021222324252627282930//COMPJOB JOB (ACCT),'COMPILE JOB',CLASS=A //* //COMPILE EXEC PGM=IKFCBL00 //SYSIN DD DSN=SOURCE.COBOL(PROGRAM),DISP=SHR //SYSLIN DD DSN=&&OBJSET,DISP=(NEW,PASS), // UNIT=SYSDA,SPACE=(TRK,(5,5)) //SYSPRINT DD SYSOUT=* //* // IF (COMPILE.RC <= 4) THEN //LINK EXEC PGM=IEWL //SYSLIN DD DSN=&&OBJSET,DISP=(OLD,DELETE) //SYSLMOD DD DSN=LOAD.LIBRARY(PROGRAM),DISP=SHR //SYSPRINT DD SYSOUT=* //* // IF (LINK.RC = 0) THEN //EXECUTE EXEC PGM=PROGRAM //STEPLIB DD DSN=LOAD.LIBRARY,DISP=SHR //SYSOUT DD SYSOUT=* //* // ELSE //LKERROR EXEC PGM=NOTIFY,PARM='LINK FAILED' //SYSPRINT DD SYSOUT=* // ENDIF //* // ELSE //CMPERROR EXEC PGM=NOTIFY,PARM='COMPILE FAILED' //SYSPRINT DD SYSOUT=* // ENDIF //* //CLEANUP EXEC PGM=IEFBR14
Using complex conditions to control the flow of a data processing job:
1234567891011121314151617181920212223242526272829303132333435363738//DATAJOB JOB (ACCT),'DATA PROCESSING',CLASS=A //* //EXTRACT EXEC PGM=EXTRACT //INPUT DD DSN=INPUT.DATA,DISP=SHR //OUTPUT DD DSN=&&TEMP1,DISP=(NEW,PASS) //SYSPRINT DD SYSOUT=* //* // IF ((EXTRACT.RC = 0) OR (EXTRACT.RC = 4)) THEN //SORT EXEC PGM=SORT //SORTIN DD DSN=&&TEMP1,DISP=(OLD,PASS) //SORTOUT DD DSN=&&TEMP2,DISP=(NEW,PASS) //SYSIN DD * SORT FIELDS=(1,10,CH,A) /* //SYSOUT DD SYSOUT=* //* // IF (SORT.RC = 0) THEN //REPORT EXEC PGM=REPORTER //INPUT DD DSN=&&TEMP2,DISP=(OLD,PASS) //OUTPUT DD DSN=REPORT.DATA,DISP=(NEW,CATLG) //SYSPRINT DD SYSOUT=* // ENDIF //* // ELSE // IF (EXTRACT.RC < 12) THEN //RECOVERY EXEC PGM=RECOVER //INPUT DD DSN=BACKUP.DATA,DISP=SHR //OUTPUT DD DSN=REPORT.DATA,DISP=(NEW,CATLG) //SYSPRINT DD SYSOUT=* // ELSE //NOTIFY EXEC PGM=NOTIFY,PARM='CRITICAL FAILURE' //SYSPRINT DD SYSOUT=* // ENDIF // ENDIF //* //CLEANUP EXEC PGM=IEFBR14,COND=EVEN //TEMP1 DD DSN=&&TEMP1,DISP=(OLD,DELETE) //TEMP2 DD DSN=&&TEMP2,DISP=(OLD,DELETE)
While IF/THEN/ELSE structures are powerful, they have some limitations to be aware of:
IF/THEN/ELSE statements must be in the main JCL stream and cannot be placed within cataloged procedures.
IF statements can only compare numeric values (return codes) and cannot directly compare strings or use complex expressions.
Conditional logic applies to entire JCL statements - you cannot conditionally specify individual parameters within a statement.
IF/THEN/ELSE structures are not available in older versions of JES. Check your system's compatibility before using.
All steps referenced in conditions must have executed previously in the job. Forward references are not allowed.
Indent your JCL consistently to clearly show the structure of nested IF/THEN/ELSE blocks. This makes the logic much easier to follow.
Include comments that explain the purpose of conditional blocks, especially for complex logic.
12//* The following conditional block handles error recovery // IF (STEP1.RC > 4) THEN
Even when not strictly required, use parentheses to make the order of operations clear in complex expressions.
For very complex logic, consider whether breaking the job into multiple simpler jobs might be more maintainable than creating deeply nested IF/THEN/ELSE structures.
Use conditional logic to gracefully handle errors and provide meaningful notifications or recovery steps.
When deciding between COND parameters and IF/THEN/ELSE structures, consider these factors:
In many cases, you can use both COND parameters and IF/THEN/ELSE structures in the same job to take advantage of their respective strengths.
Test your understanding of IF/THEN/ELSE structures with these exercises:
Create a JCL job with three steps. Use an IF/THEN/ELSE statement to run PROGA if STEP1 has a return code of 0, otherwise run PROGB.
1234567891011//EXERJOB JOB (ACCT),'IF/THEN EXERCISE',CLASS=A //STEP1 EXEC PGM=MYPROG //SYSOUT DD SYSOUT=* //* // IF (STEP1.RC = 0) THEN //STEP2A EXEC PGM=PROGA //SYSOUT DD SYSOUT=* // ELSE //STEP2B EXEC PGM=PROGB //SYSOUT DD SYSOUT=* // ENDIF
Create a JCL job that runs a step only if both STEP1 and STEP2 had a return code of 0 or 4.
1234567891011//EXERJOB JOB (ACCT),'LOGICAL OPS',CLASS=A //STEP1 EXEC PGM=MYPROG1 //SYSOUT DD SYSOUT=* //* //STEP2 EXEC PGM=MYPROG2 //SYSOUT DD SYSOUT=* //* // IF ((STEP1.RC LE 4) AND (STEP2.RC LE 4)) THEN //STEP3 EXEC PGM=MYPROG3 //SYSOUT DD SYSOUT=* // ENDIF
Create a JCL job with nested IF statements: If STEP1's return code is 0, run PROGA; if it's 4, run PROGB; otherwise, run PROGC.
12345678910111213141516//EXERJOB JOB (ACCT),'NESTED IF',CLASS=A //STEP1 EXEC PGM=MYPROG //SYSOUT DD SYSOUT=* //* // IF (STEP1.RC = 0) THEN //STEPA EXEC PGM=PROGA //SYSOUT DD SYSOUT=* // ELSE // IF (STEP1.RC = 4) THEN //STEPB EXEC PGM=PROGB //SYSOUT DD SYSOUT=* // ELSE //STEPC EXEC PGM=PROGC //SYSOUT DD SYSOUT=* // ENDIF // ENDIF
1. Which statement marks the end of a conditional block in JCL?
2. Which of the following is a valid comparison operator in JCL IF statements?
3. What logical operators are supported in JCL IF statements?
4. How would you test if a step named STEP1 returned a code less than or equal to 4?
5. Which of the following statements would correctly test for a return code of 0 OR 4?
6. Which of the following is NOT a valid RC reference in JCL?