CL, short for Control Language, is the command language of IBM i. Every command you type on a command line is CL, and a CL program is a sequence of those commands with variables, decisions and error handling around them. It is the orchestration layer: it runs commands, calls programs, submits jobs and reacts when something fails. Large business logic usually belongs in RPGLE or another application language.
Commands Are the Building Blocks
A CL command is a verb and an object, written in capitals by convention, followed by named parameters:
CRTLIB LIB(DEMOLIB) TEXT('Demo library')
DSPLIBL
WRKACTJOB
The prefix tells you the action (CRT create, CHG change, DLT delete, DSP display, WRK work with, ADD, RMV, STR start, END end) and the rest names the thing. Press F4 on any command to prompt it, and F1 for help on a parameter. Most CL commands are the same ones you use interactively, which is why CL feels natural once you know the platform.
A Small CL Program
CL source goes in a source member of type CLLE. This program clears a work file, copies data into it and reports what happened:
PGM PARM(&RUNDATE)
DCL VAR(&RUNDATE) TYPE(*CHAR) LEN(8)
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
RTVJOBA USER(&USER)
/* Remove yesterday's work file; ignore "file not found" */
DLTF FILE(QTEMP/WORKORD)
MONMSG MSGID(CPF2105)
CRTDUPOBJ OBJ(ORDERS) FROMLIB(PRODLIB) OBJTYPE(*FILE) +
TOLIB(QTEMP) NEWOBJ(WORKORD) DATA(*NO)
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FAILED))
CALL PGM(APPLIB/BLDORDERS) PARM(&RUNDATE)
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FAILED))
SNDPGMMSG MSG('Order build finished for ' *CAT &RUNDATE *CAT ' by ' *CAT &USER) +
TOPGMQ(*EXT)
RETURN
FAILED:
SNDPGMMSG MSG('Order build failed. See the job log.') TOPGMQ(*EXT)
RETURN
ENDPGM
Compile it into a program object and run it:
CRTBNDCL PGM(APPLIB/ORDBUILD) SRCFILE(APPLIB/QCLLESRC) SRCMBR(ORDBUILD)
CALL PGM(APPLIB/ORDBUILD) PARM('20261005')
Points to notice:
PGMandENDPGMframe the program, andPARM(&RUNDATE)declares the parameter. The variable is declared withDCLand is typed:*CHAR,*DEC,*INT,*LGL.- Variables begin with
&.CHGVARassigns values, and*CATjoins strings. RTVJOBAretrieves attributes of the current job into variables. TheRTVcommands are how CL reads information.MONMSGhandles errors (below).QTEMPis a library private to the job, which makes it a good place for work files.
Flow Control
CL has the usual structures, with commands rather than keywords:
IF COND(&RC *EQ 0) THEN(DO)
/* success */
ENDDO
ELSE DO
/* failure */
ENDDO
DOWHILE COND(&COUNT *LT 5)
CHGVAR VAR(&COUNT) VALUE(&COUNT + 1)
ENDDO
SELECT
WHEN COND(&TYPE *EQ 'A') THEN(CALL PGM(DOA))
OTHERWISE CMD(CALL PGM(DOOTHER))
ENDSELECT
Comparisons use *EQ, *NE, *LT, *GT, *LE, *GE, and logical operators are *AND, *OR, *NOT. GOTO CMDLBL(label) jumps to a label, which is how the error paths in the earlier example work.
Handling Errors with MONMSG
Every failing command sends an escape message, such as CPF2105 (“file not found”), to the program. If nothing monitors for it, the program stops with an inquiry message that waits for an operator. MONMSG tells CL what to do instead:
- Placed directly after a command, it covers that command:
MONMSG MSGID(CPF2105)ignores the error, orMONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FAILED))branches. CPF0000is a generic ID that matches everyCPFmessage, which makes it handy for a catch-all.- Placed straight after
PGMand the declarations, with noEXEC, it covers the whole program.
Catching everything quietly hides real problems, so monitor for the specific message when you can and log the rest. The CL error handling guides on this site go into message types, RCVMSG and structured patterns: start with IBM i Message Files, Exception Handling and CL.
Running Work in the Background
Batch work is usually submitted rather than run in your session:
SBMJOB CMD(CALL PGM(APPLIB/ORDBUILD) PARM('20261005')) JOB(ORDBUILD) JOBQ(QBATCH)
SBMJOB queues the command as a separate job. To run work on a schedule instead, use job schedule entries; see IBM i Job Scheduling.
Variables and Data Types
CL variables are declared before use and are typed. The ones you will use most:
| Type | Use |
|---|---|
*CHAR | Text, with a length: DCL VAR(&NAME) TYPE(*CHAR) LEN(30) |
*DEC | Packed numbers: DCL VAR(&AMT) TYPE(*DEC) LEN(9 2) |
*INT | Whole numbers |
*LGL | Logical, '1' or '0': DCL VAR(&OK) TYPE(*LGL) VALUE('0') |
Variables are not case sensitive and names can be up to 10 characters after the &. A program parameter is a variable too, and parameters are passed by reference, so a called program can change a value you pass it. Declare a parameter with the length the caller uses: a mismatch is a classic source of truncated or garbled values.
Seeing What Happened
When a CL program fails, the job log is the first place to look:
DSPJOBLOG
WRKJOB OPTION(4)
For a batch job, the job log is written to a spooled file, which you can open with WRKSPLF. To step through a CL program, compile it with a debug view and start debug before running it:
CRTBNDCL PGM(APPLIB/ORDBUILD) SRCFILE(APPLIB/QCLLESRC) SRCMBR(ORDBUILD) DBGVIEW(*SOURCE)
STRDBG PGM(APPLIB/ORDBUILD)
Adding SNDPGMMSG calls at key points, as in the example, makes the job log tell the story of a run, which saves time later.
Good Habits
- Put one job’s work in one program and give it a clear name.
- Monitor for specific messages and let unexpected ones fail loudly.
- Keep business rules out of CL; call RPG or SQL for them.
- Use
QTEMPfor work objects and clean them up at the start, as the example does. - Send a completion or failure message that an operator can find.
Passing Parameters Between Programs
CALL passes parameters positionally, and the called program declares them in the same order. A CL program can call another CL program, an RPG program, or a program in any other ILE language.
PGM
DCL VAR(&CUSTNO) TYPE(*CHAR) LEN(8) VALUE('00012345')
DCL VAR(&STATUS) TYPE(*CHAR) LEN(1)
CALL PGM(APPLIB/CUSTCHECK) PARM(&CUSTNO &STATUS)
IF COND(&STATUS *EQ 'E') THEN(SNDPGMMSG MSG('Customer check failed') TOPGMQ(*EXT))
ENDPGM
The called program receives the address of each value, not a copy. If it changes &STATUS, the caller sees the change. That is useful for returning a result and dangerous if the lengths do not match, so keep parameter definitions in one place, such as a shared copy member for RPG callers.
Commands You Will Use Every Week
WRKACTJOBandWRKJOBto see running jobs, andDSPJOBLOGfor what a job did.WRKOUTQandWRKSPLFfor spooled output.DSPLIBL,ADDLIBLEandWRKOBJfor the object model.CPYFto copy data between files, andDLTF,CRTPFfor file work.CHGVAR,RTVJOBA,RTVSYSVALto read and set values inside a program.SBMJOB,HLDJOB,RLSJOB,ENDJOBto control batch work.
Each of these is documented in IBM’s CL command reference, and F4 shows the parameters on your own release.
Where CL and RPGLE Meet
A common pattern is a thin CL program around an RPGLE program: CL sets the library list, overrides files, calls the RPG program, checks for errors and sends the result to operators. The RPG program does the business logic and CL does the plumbing. That separation keeps both simple.
Summary
CL is the glue of IBM i. It runs the same commands you type, adds typed variables, flow control and MONMSG error handling, and submits work with SBMJOB. Write small programs that call your RPG or SQL, check every step, and say clearly when something fails.
Learning Path
- Command syntax and prompting (F4, F1).
- Calling programs and passing parameters.
- Variables,
CHGVAR, and theRTVcommands. - Flow control and
MONMSG. SBMJOB, job queues and scheduling.- Message handling in depth.
Keep reading with IBM i Libraries, Objects, and Members Explained if the object names above are unfamiliar.