cheat sheet
ISPF Edit
Deep dive into the ISPF editor — primary commands, line commands, BNDS/CC/MM column edits, ISREDIT macro services, profile management, and recovery.
ISPF Edit — Primary commands, line commands, macros, and column-mode editing
What it is
ISPF Edit (option 2 in ISPF, also reached via EDIT 'dsname' from TSO READY) is the full-screen editor that mainframe developers use for source, JCL, REXX, and parameter datasets — a sibling of View and Browse, but with destructive writes and a recoverable undo log. The editor is shipped by IBM as part of ISPF and has been the canonical mainframe code editor for decades. Reach for Edit whenever a dataset must be modified in place: changing JCL parameters, fixing a COBOL source line, tweaking a CLIST. For anything you only need to read, prefer View or Browse — they cannot accidentally destroy data and are usually available even when Edit is locked by another user.
This page is a deep companion to tso-ispf, focused exclusively on the Edit panel: every primary command, every line command, the column-mode editing pattern using BNDS/CC/MM, the ISREDIT macro programming interface, edit-profile management, and recovery.
z/OS 3.2 (GA 30 September 2025) ISPF Edit additions: PDSE V2 member generations are now first-class — EDIT 'pdse(member)' GEN(n) and BROWSE accept an explicit generation number, and a generation list is viewable for members with generations. The z/OS UNIX Directory List Utility offers a case-insensitive sort option for large directories. The z/OSMF Desktop Editor (APAR PH34912) lets dataset names and USS file paths render as clickable links — useful when staying off the 3270 entirely. For greenfield mainframe development, the Zowe Explorer VS Code extension is the IBM-recommended complement to ISPF Edit for IDE-resident workflows (datasets, USS files, JCL submit, TSO command issue) without replacing ISPF's local-edit semantics.
Entering Edit
Edit is opened either through an ISPF panel chain or directly from TSO. The fastest paths are option 2 (free-form dataset prompt), option 3.4 (DSLIST), or option =2 from any panel — = jumps the panel stack.
=2 (* Edit panel — type dataset and press Enter *)
=3.4 (* DSLIST — then 'E' next to the dataset row *)
EDIT 'ALICE.JCL.LIB(ALICEJ01)' (* From READY prompt — quoted = fully qualified *)
EDIT ALICE.SOURCE (* Unquoted — your prefix is prepended *)
EDIT JCL(NEWJOB) NEW (* Allocate-and-edit a new member if missing *)
Output: (none — opens the Edit panel)
From DSLIST you can also queue E against several rows; each opens in sequence, and END (PF3) moves to the next.
Edit screen anatomy
The Edit display has four regions you need to know cold: the command line, the prefix area (line numbers / line commands), the data area, and the message area. Understanding which keystroke goes where is the difference between fluent editing and constant RESET calls.
File Edit Edit_Settings Menu Utilities Compilers Test Help
─────────────────────────────────────────────────────────────────
EDIT ALICE.JCL.LIB(ALICEJ01) Columns 00001 00072
Command ===> Scroll ===> CSR
****** ***************************** Top of Data ******************************
000100 //ALICEJ01 JOB (ACCT),'ALICE DEV',CLASS=A,MSGCLASS=X,
000200 // NOTIFY=&SYSUID,REGION=0M
000300 //STEP01 EXEC PGM=IEFBR14
000400 //NEWDS DD DSN=ALICE.NEW.DATA,
000500 // DISP=(NEW,CATLG,DELETE),
000600 // SPACE=(CYL,(5,2)),
000700 // DCB=(RECFM=FB,LRECL=80)
****** **************************** Bottom of Data ****************************
Output: (none — exits 0 on success)
- Command line (
Command ===>) accepts primary commands likeFIND,CHANGE,EXCLUDE,RESET. - Prefix area (the leftmost 6 chars, typically line numbers) accepts line commands like
D,C5,RR,MM. - Data area is the visible record content from column 1 to the right margin (typically 72 for fixed-block 80, or
LRECLfor variable). - Scroll field (
Scroll ===>) takesPAGE,HALF,CSR,DATA, or an integer.
Primary commands
Primary commands are typed on the Command ===> line and act on the buffer as a whole, the current cursor position, or a .label range. They are the equivalent of :command mode in vi or M-x in Emacs.
FIND / RFIND
FIND searches the buffer for a string starting at the cursor and stops at the first hit; RFIND (PF5) repeats the last FIND in the same direction. By default the search is case-insensitive and respects the current BOUNDS setting.
FIND ABEND (* find next "ABEND" *)
F ABEND FIRST (* first occurrence from top *)
F ABEND LAST (* last occurrence *)
F ABEND ALL (* show count, position at first hit *)
F ABEND PREV (* search backward *)
F 'literal string' (* preserve case and embedded spaces *)
F C'CICS' (* same as above using "C" prefix *)
F X'C8C5D3D3D6' (* hex search — finds the EBCDIC bytes "HELLO"*)
F P'#' (* picture: any numeric digit *)
F P'@' (* picture: any alphabetic char *)
F P'=' (* picture: any non-blank *)
F P'<' (* picture: any lowercase letter *)
F P'>' (* picture: any uppercase letter *)
F ABEND WORD (* whole word only *)
F ABEND PREFIX (* matches "ABENDED" but not "TABEND" *)
F ABEND SUFFIX (* matches "TABEND" but not "ABENDED" *)
F ABEND 10 30 (* restrict to columns 10–30 for this find *)
F ABEND .START .END (* restrict to labeled range .START..END *)
Output:
CHARS 'ABEND' found 3 times.
CHANGE / RCHANGE
CHANGE (alias C on the command line) substitutes one string for another. Like FIND, it accepts pictures, hex, and column/label ranges, plus an ALL keyword for global replace. RCHANGE (PF6) repeats the last change forward.
C OLDFLD NEWFLD (* change next OLDFLD to NEWFLD *)
C OLDFLD NEWFLD ALL (* change all *)
C OLDFLD NEWFLD ALL 10 30 (* only within columns 10–30 *)
C P'#' '0' ALL (* zap every digit to 0 *)
C X'5A' X'7B' ALL (* swap EBCDIC '!' (5A) for '#' (7B) *)
C 'DSN=ALICE.OLD' 'DSN=ALICE.NEW' ALL
C 'PROD' 'TEST' ALL .DATAONLY (* range limited by labels .DATAONLY.. *)
Output:
CHARS 'OLDFLD' changed 4 times.
When the new string is longer than the old, ISPF asks whether to push subsequent text right; if shorter, it asks whether to pull left. The default is governed by the PROFILE (STATS, NULLS, etc.) — see Edit profile below.
LOCATE / LOC
LOCATE jumps the cursor to a specific line. The argument can be an integer line number, a .label, a column-name like FIRST or LAST, or a relative offset.
LOC 100 (* line number 100 *)
LOC .ENTRY (* user-defined label set with .ENTRY in prefix*)
LOC FIRST (* top of data *)
LOC LAST (* bottom of data *)
LOC +50 (* 50 lines forward *)
LOC -20 (* 20 lines back *)
LOC X (* next excluded block *)
LOC NX (* next non-excluded line *)
LOC LABEL (* next labeled line *)
LOC CHA (* next changed line *)
LOC ERR (* next error line (e.g. compiled with err) *)
LOC SPE (* next special line — marker line *)
LOC ALL CHA .START .END (* show all changed lines in labeled range *)
Output: (none — the cursor moves to the matching line)
EXCLUDE / X / RESET / FLIP
EXCLUDE hides lines so you can focus on what remains; RESET brings them back. Combined with FIND, this is the canonical way to filter a 200,000-line dataset to just the rows you care about.
X ABEND ALL (* hide every line containing ABEND *)
X ALL (* hide everything *)
X P'#' ALL (* hide all lines containing a digit *)
RESET (* show all excluded lines, clear highlights *)
RESET EXC (* show excluded — keep find/change highlights*)
RESET FIND (* clear find highlights only *)
RESET CHANGE (* clear change highlights only *)
RESET LABEL (* clear all user labels *)
RESET COMMAND (* clear pending prefix commands *)
FLIP (* swap visible <-> excluded *)
FLIP .S .E (* flip only within labeled range *)
Output:
73 LINE(S) NOT DISPLAYED.
BOUNDS / BNDS
BOUNDS restricts FIND, CHANGE, SORT, and several line commands to a column range. Display the bounds line with the BNDS line command (covered below) and overtype the < and > markers; or set them numerically from the command line.
BOUNDS 16 71 (* restrict to JCL operand columns 16–71 *)
BOUNDS * (* show current bounds *)
BOUNDS (* reset to default (1, record length) *)
Output:
BOUNDS SET TO 16 71.
HEX
HEX toggles a 2-row hex display under each data line — top row holds the high nibble, bottom row the low nibble, both read top-down. Essential for diagnosing unprintable characters, tagging issues, or chasing EBCDIC vs ASCII mismatches.
HEX ON (* default: VERT — two rows under each data line *)
HEX ON VERT (* explicit vertical layout *)
HEX ON DATA (* hex appended to the right of each data line *)
HEX OFF (* turn off *)
Output (a single record HELLO with HEX ON VERT):
000100 HELLO
CCCCC
8556F
The "C8 C5 D3 D3 D6" reads down: H=C8, E=C5, L=D3, L=D3, O=D6.
CAPS / NULLS / NUMBER / RENUM / UNNUM
These commands control how text you type is stored and how the prefix area is rendered. They are each one-line settings; combined with PROFILE (below) they form the editor's "vim modeline" equivalent.
CAPS ON (* fold every keystroke to uppercase *)
CAPS OFF (* preserve mixed case (typical for REXX, PL/I)*)
NULLS ON (* trailing nulls — overtype past end of data *)
NULLS ON ALL (* convert trailing blanks to nulls on save *)
NULLS OFF (* trailing blanks — append blocked at EOR *)
NUMBER ON STD (* show standard sequence numbers cols 73–80 *)
NUMBER ON COB (* COBOL sequence numbers in cols 1–6 *)
NUMBER ON RELATIVE (* relative numbering — recalc on every save *)
NUMBER OFF (* hide sequence numbers (still in record) *)
RENUM (* re-sequence existing numbers 100, 200, ... *)
RENUM 10 10 (* start at 10, increment 10 *)
UNNUM (* delete sequence numbers from the records *)
AUTONUM ON (* renumber automatically on every save *)
Output: (none — exits 0 on success)
TABS
TABS defines logical tab stops for inserting columnar data — useful for COBOL Area A/B or DDL alignment. Combined with the TS (Text Split) line command, it gives you a low-budget structured-text editor.
TABS ON (* enable tab processing *)
TABS 8 12 16 36 73 (* numeric stops at these columns *)
TABS OFF
TABS * (* report current stops *)
Output: (none — exits 0 on success)
UNDO / REDO
UNDO reverses the most recent edit transaction; REDO re-applies it. SETUNDO STORAGE is the prerequisite — without it, undo is disabled by site default.
SETUNDO STORAGE (* enable in-memory undo for this session *)
SETUNDO STG (* synonym *)
SETUNDO FORCE (* enable even when RECOVERY is OFF *)
SETUNDO OFF
UNDO (* roll back last logical change *)
REDO (* re-apply the change just undone *)
Output:
EDIT changes UNDONE.
MD — make dataline
MD strips the special line types — notes, MSG lines, info lines from MODEL, exclude-line markers — and turns them into real data records. Useful when you have just generated a JCL or COBOL skeleton via MODEL and want to commit it.
MD .ZF .ZL (* convert all info lines in labeled range *)
MD ALL (* convert every non-data line in the file *)
Output: (none — exits 0 on success)
Other useful primary commands
COLS, SORT, SUBMIT, SAVE, CANCEL, CREATE, REPLACE, and MOVE are common companions to the daily commands above.
COLS (* show a column ruler on the next line *)
COL (* synonym *)
SORT 1 80 (* sort all records by columns 1–80 ascending *)
SORT 1 8 A 73 5 D (* primary key 1-8 ASC, secondary 73-77 DESC *)
SUBMIT (* submit the current buffer as JCL *)
SUBMIT .S .E (* submit only the labeled range as a job *)
SAVE (* save without leaving Edit *)
CANCEL (* abandon changes since last save *)
CREATE ALICE.SNIP (* copy selection or labeled range to dsname *)
REPLACE ALICE.MEM(NEWMEM) (* save selection to a new PDS member *)
MOVE (* copy/move from another dataset/member *)
COPY (* synonym for MOVE *)
EDIT 'ALICE.SECOND' SUBSET (* open a sub-edit (split-screen alternative) *)
Output: (none — exits 0 on success)
Line commands
Line commands are typed in the prefix area (the 6-character field on the left). They act on a single line, a range (Dn, D5, Cn), or a paired block (DD...DD, CC...CC, MM...MM). When the cursor leaves the prefix area or you press Enter, all pending line commands run together.
Cursor and structural commands
I (* insert one blank line BELOW *)
I5 (* insert five blank lines *)
TS (* text-split — break the line at the cursor *)
TJ (* text-join — join with the next line *)
TE (* text-entry — insert mode, ends with first blank line *)
TF (* text-flow — reflow paragraph to right margin *)
COLS (* place a column ruler under this line *)
TABS (* place a tab ruler under this line *)
MASK (* edit the mask used by INSERT — fixed columns auto-filled *)
BNDS (* place an editable BOUNDS ruler *)
.LBL (* place a user label "LBL" on this line *)
Output: (none — exits 0 on success)
Delete, copy, move, repeat, exclude
D, C, M, R, and X are the workhorses. Numeric suffix means "this many lines from here"; doubled letters delimit a block (DD...DD, etc.).
| Single | Block | Numeric | Meaning |
|---|---|---|---|
D | DD...DD | D5 | Delete |
C | CC...CC | C3 | Copy (pair with A or B) |
M | MM...MM | M2 | Move (pair with A or B) |
R | RR...RR | R10 | Repeat |
X | XX...XX | X4 | Exclude |
S | — | S5 | Show n hidden lines from this block |
F | — | — | Show first hidden line of this excluded block |
L | — | — | Show last hidden line of this excluded block |
LC | LC...LC | LC3 | Lowercase |
UC | UC...UC | UC3 | Uppercase |
O | OO...OO | O5 | Overlay — paste over n lines (non-blank wins) |
( ) < > | (( )) << >> | (5 | Shift left/right (data shift, no truncation if blanks) |
[ ] | [[ ]] | [5 | Shift left/right (column shift — can truncate) |
P | — | — | Print the line to the ISPF list dataset |
W | — | — | Write to dataset (prompts) |
Examples of usage:
000100 //JOB ...
D00200 //STEP01 ... (* D in prefix deletes this line *)
000300 //STEP02 ...
R3 000400 //STEP03 ... (* R3 repeats line 4 three times *)
000500 //STEP04 ...
CC 000200 (* start copy block here *)
000300
CC 000400 (* end copy block — these 3 lines are copied*)
A 000500 (* paste after this line *)
MM 000200 (* start move block here *)
MM 000400 (* end move block *)
B 000700 (* paste before this line *)
X10 000200 (* exclude 10 lines from here *)
Output (after the R3 command runs):
000400 //STEP03 ...
'''''' //STEP03 ...
'''''' //STEP03 ...
'''''' //STEP03 ...
(Apostrophes in the prefix area mark inserted "ditto" lines until you save or assign sequence numbers.)
A / B / O — destinations
A (after), B (before), and O (overlay) are destination line commands. They are illegal on their own — every C/M/CC/MM requires a paired destination before you press Enter, or ISPF returns NO 'A' OR 'B' LINE COMMAND..
CC ... (* mark source block *)
CC ...
A (* paste 1 copy after this line *)
CC ... (* mark source block *)
CC ...
A5 (* paste 5 copies after this line *)
MM ... (* mark source *)
MM ...
B (* paste before, removing the source *)
CC ... (* mark source *)
CC ...
OO ... (* overlay range *)
OO ...
Output: (none — exits 0 on success)
Overlay semantics — O / OO
Overlay merges the source into the destination column by column: for each column, the source character wins unless the source is a blank, in which case the destination character is preserved. This is the basis of column-mode editing (next section).
Source block (1 line): ----+----X----- (* blanks except col 10 *)
Destination block: //OLD INPUT
After OO/O paste: //OLD X INPUT
Output: (none — exits 0 on success)
Column-mode editing — BNDS + CC + MM + OO
Column-mode editing is the ISPF idiom for "edit just these columns across these rows" — vertically. It combines four commands: BNDS to limit the column range, CC...CC to copy a narrow source from one set of lines, and OO...OO to overlay it onto another set. The result is a true column-wise edit without a regex engine.
Recipe — change columns 16-25 across 50 lines
Suppose you have a JCL with 50 DD statements and you need to change a path component buried in columns 16-25 of every line. The conventional approach (CHANGE) only works if the substring is unique; column-mode editing works regardless.
Step 1 — set bounds to the columns you care about:
Command ===> BOUNDS 16 25
Step 2 — at the line that already has the correct value, mark a 1-line CC block:
CC 000100 //DD01 DD DSN=ALICE.NEW.LIB(MEMA),DISP=SHR
CC 000100 //DD01 DD DSN=ALICE.NEW.LIB(MEMA),DISP=SHR
Step 3 — at the first and last lines that need to be overlaid, mark OO...OO:
OO 000200 //DD02 DD DSN=ALICE.OLD.LIB(MEMB),DISP=SHR
...
OO 000250 //DD50 DD DSN=ALICE.OLD.LIB(MEMZ),DISP=SHR
Output: (none — every overlaid row now reads ALICE.NEW in columns 16-25; everything outside the bounds is untouched)
Recipe — strip a column range without deleting lines
Combine BNDS with a CC block of a single blank line and OO over the targets to wipe columns clean while preserving line structure.
Command ===> BOUNDS 73 80
CC ........ (* 1 blank line — source pad *)
CC ........
OO 000100 ... (* every row in the OO block *)
OO 000999 ... (* gets columns 73-80 blanked *)
Output: (none — exits 0 on success)
Recipe — duplicate a 5-column "value" across N rows
This is how you set a constant value into a fixed slice of every line in a section without writing a REXX macro.
Command ===> BOUNDS 30 34
CC 000100 ...........TEST.. (* line containing "TEST " in cols 30-34 *)
CC 000100 ...........TEST..
OO 000200 ... (* range of rows where columns 30-34 *)
OO 000300 ... (* should be overlaid with "TEST " *)
Output: (none — exits 0 on success)
Labels
Labels are user-defined symbolic names attached to a line (e.g. .S, .E, .ABEND). They appear in the prefix area and survive scrolling. Most primary commands accept a .label .label range to scope an action; LOCATE .label jumps to one.
.START 000100 //ALICEJ01 JOB ... (* set label .START *)
.END 000999 //*END OF JOB (* set label .END *)
Command ===> X ALL .START .END (* exclude only lines in that range *)
Command ===> C 'PROD' 'TEST' ALL .START .END
Command ===> LOC .ABEND
Command ===> RESET LABEL (* clear every user label *)
Output: (none — exits 0 on success)
Reserved system labels (set automatically and updated by ISPF) include .ZF (Z-First — top of file), .ZL (Z-Last — bottom), .ZFIRST, .ZLAST, and .ZCSR (current cursor line).
Edit profile
An edit profile groups settings (CAPS, NULLS, NUMBER, HEX, HILITE, RECOVERY, STATS, IMACRO, etc.) and is selected automatically by the dataset's last qualifier (JCL, COBOL, REXX, etc.) or the explicit PROFILE name command. Each user has up to 25 profiles cached in ISPF.ISPPROF.
PROFILE (* show current profile settings *)
PROFILE JCL (* switch to (or create) JCL profile *)
PROFILE LOCK (* prevent ISPF from auto-switching profiles *)
PROFILE UNLOCK
PROFILE RESET (* delete profile and recreate from site defaults*)
PROFILE NUMBER OFF
PROFILE CAPS OFF (* persist setting in current profile *)
PROFILE HILITE JCL CURSOR (* JCL highlight + cursor-line emphasis *)
PROFILE RECOVERY ON (* recoverable across crashes via journal DS *)
PROFILE STATS ON (* maintain modification stats on members *)
PROFILE IMACRO JCLINIT (* auto-run macro JCLINIT on open *)
PROFILE PACK ON (* compressed storage format *)
PROFILE NOTE ON (* show note lines from prior actions *)
Output (PROFILE):
....JCL (FIXED - 80)....RECOVERY ON....NUMBER OFF STD....CAPS ON....
HEX OFF....NULLS ON....TABS OFF....AUTOSAVE ON PROMPT....AUTONUM OFF....
AUTOLIST OFF....STATS ON....PROFILE UNLOCK....IMACRO NONE....
PACK OFF....NOTE ON....HILITE JCL CURSOR FIND....
The profile name in the first parens (JCL) is what PROFILE switches between; you can have a JCL, COBOL, REXX, ASM, PLI, and arbitrary user profiles like MYNOTES.
Syntax highlighting — HILITE
HILITE controls real-time syntax coloring. The recognized languages cover everything common in z/OS development plus a AUTO mode that picks from the dataset's last qualifier.
HILITE JCL (* JCL syntax coloring *)
HILITE COBOL
HILITE PLI
HILITE ASM
HILITE REXX
HILITE SQL
HILITE PASCAL
HILITE C
HILITE HTML
HILITE OTHER (* generic — comment/string only *)
HILITE AUTO (* match by dataset name *)
HILITE OFF
HILITE JCL CURSOR (* JCL + highlight cursor line *)
HILITE JCL FIND (* JCL + highlight FIND hits *)
HILITE PAREN (* show matching parentheses *)
HILITE LOGIC (* highlight nested IF/DO blocks *)
HILITE NOLOGIC
Output: (none — exits 0 on success)
Recovery
Edit recovery is a journal dataset (one per user) that captures every edit transaction. If your session abends or the system goes down, your next Edit on the same dataset offers to replay the journal. PROFILE RECOVERY ON is required.
PROFILE RECOVERY ON (* enable per-profile *)
PROFILE RECOVERY OFF (* disable *)
On re-entry to a dataset whose journal has uncommitted edits, ISPF shows a RECOVERY? prompt:
Recovery has been requested.
This member was being edited during a previous session.
ENTER: continue recovery ABORT: cancel recovery
DEFER: defer recovery
Enter re-applies every change; CANCEL (PF12) leaves the dataset untouched; DEFER keeps the journal entries for next time. The recovery dataset name is set in ISPF Settings (=0 → Edit Recovery), default userid.SPFTEMP1.CNTL.
Edit macros — ISREDIT services
An edit macro is a REXX, CLIST, or compiled program that uses the ISREDIT service interface to inspect and modify the buffer. Macros live in any dataset on SYSPROC or SYSEXEC, and run from the command line just like a primary command. They are the way to script ISPF Edit.
A minimal REXX macro that uppercases every line containing "TODO":
/* REXX */
"ISREDIT MACRO" /* declare as macro */
"ISREDIT (LAST) = LINENUM .ZL" /* total line count */
do i = 1 to LAST
"ISREDIT (LINE) = LINE " i /* get line text */
if pos("TODO", LINE) > 0 then do
upper LINE /* REXX upper */
"ISREDIT LINE " i " = (LINE)" /* write it back */
end
end
"ISREDIT (COUNT) = USER_STATE" /* save cursor/scroll */
exit 0
Output: (none — exits 0 on success)
Common ISREDIT services
Every service is invoked via ADDRESS ISREDIT "command" (or "ISREDIT command" once ADDRESS ISREDIT is the default). Below is the working set; the full reference is in ISPF Edit and Edit Macros (SC19-3621).
ISREDIT MACRO (* declare this REXX as a macro *)
ISREDIT MACRO (P1 P2 P3) (* accept positional parameters *)
ISREDIT MACRO PROCESS (* process pending line commands *)
ISREDIT (LAST) = LINENUM .ZL (* number of last line in buffer *)
ISREDIT (CUR) = LINENUM .ZCSR (* cursor line number *)
ISREDIT (FIRST) = LINENUM .ZF (* first line *)
ISREDIT (LINE) = LINE n (* read line n into REXX var *)
ISREDIT LINE n = (LINE) (* write REXX var into line n *)
ISREDIT LINE_AFTER n = (NEW) (* insert NEW after line n *)
ISREDIT LINE_BEFORE n = (NEW) (* insert NEW before line n *)
ISREDIT DELETE n (* delete one line *)
ISREDIT DELETE n m (* delete range n..m *)
ISREDIT DELETE X ALL (* delete all excluded lines *)
ISREDIT DELETE NX ALL (* delete all non-excluded lines *)
ISREDIT FIND 'string' [FIRST|NEXT|LAST|PREV|ALL] [WORD|PREFIX|SUFFIX]
ISREDIT CHANGE 'old' 'new' ALL
ISREDIT EXCLUDE 'string' ALL
ISREDIT RESET
ISREDIT LOCATE n
ISREDIT LABEL n = .MYTAG (* set label .MYTAG on line n *)
ISREDIT CURSOR = n (* move cursor to line n *)
ISREDIT CURSOR = n c (* move cursor to (line n, col c) *)
ISREDIT (ROW COL) = CURSOR (* read cursor row & column *)
ISREDIT (P1 P2 ... PN) = PARM (* accept primary command tokens *)
ISREDIT (REC) = RECFM (* record format: F, V, U *)
ISREDIT (LRECL) = LRECL (* logical record length *)
ISREDIT (DSN) = DATASET (* full dataset(member) name *)
ISREDIT SAVE (* save changes without leaving *)
ISREDIT END SAVE (* save and end *)
ISREDIT CANCEL (* abandon changes, end edit *)
ISREDIT SUBMIT (* submit buffer as JCL *)
ISREDIT BUILTIN cmd (* run editor cmd even if shadow *)
ISREDIT MSG = 'message text' (* set the short message line *)
Output: (none — exits 0 on success)
Running a macro
Put the macro REXX in a dataset allocated to SYSPROC (CLIST library) or SYSEXEC (REXX library) — typically userid.EXEC or a team library. From any Edit session, invoke it by name:
Command ===> TODOUC (* runs userid.EXEC(TODOUC) *)
Command ===> TODOUC FIRST (* with a parameter *)
Command ===> %TODOUC (* explicit "%" runs implicit EXEC*)
Output: (none — exits 0 on success)
To make a macro run automatically when you open a specific profile, set the IMACRO:
PROFILE IMACRO TODOUC
Output: (none — exits 0 on success)
Useful ready-made macros from site libraries
Most shops ship a starter set under SYS1.SISPMACS or similar. Names vary, but the common ones are:
| Macro | What it does |
|---|---|
COMPARE | Side-by-side diff with another dataset (the underlying engine of SuperC) |
INDENT | Indents COBOL paragraphs or REXX do/end blocks consistently |
STRIP | Removes trailing blanks and sequence numbers |
LBOX | Draws a box around a selected block using * and - |
TOUCH | Touch ISPF stats (modify date) without changing data |
ADDREM | Add/remove a comment prefix to a labeled range |
Common pitfalls
CHANGE … ALLthenCANCEL—CANCELreverts since the lastSAVE, so running a destructive change and then closing with PF3 saves it. AlwaysSAVEbefore risky operations or setRECOVERY ON.CCblock withoutA/B— pressing Enter clears all pending commands with an error. Always queue the destination on the same Enter as the source.HEX ONmixed withINSERT— typing in the hex area silently overlays the data area. Toggle hex off before inserting.CAPS ONon a REXX file — every line you touch goes to uppercase, breaking case-sensitive REXX variables. Always setPROFILE CAPS OFFfor REXX, C, Java, Python, USS shell, and any mixed-case source.- Forgetting
BOUNDS *after column work — leftover bounds silently scope futureCHANGEcommands.BOUNDS *to inspect,BOUNDS(no args) to reset. - No
RECOVERYprofile — a 3270 disconnect loses every keystroke since the lastSAVE.PROFILE RECOVERY ONadds a small journal-dataset overhead but is worth it. - Saving a record over
LRECL— Edit truncates without warning when the new content overflows the right boundary. Watch the upper-rightColumns nnnnnindicator. PROFILE LOCKset by accident — locks the profile so language-specific defaults stop working when you open a.COBOLmember.PROFILE UNLOCKrestores auto-switching.- Running a macro that uses
ADDRESS TSOwithoutSIGNAL ON ERROR— the macro fails silently and the editor pretends success. Always wireSIGNAL ON ERRORandSAY RCin macro REXX while developing. UNDOafterSAVE— once you save, the undo log is committed and earlier transactions are gone. UseSETUNDO STORAGEtogether with manual saves only at known-good points.
Real-world recipes
Replace a hard-coded dataset prefix across a PDS
Walk every member, switch a JCL prefix from ALICE.OLD to ALICE.NEW, save and move on. The fastest path is option 3.4 → M on the PDS row → enter a one-line edit macro per member, but SUPERCE with the change dataset option also works.
Macro: REPFX (in userid.EXEC)
─────────────────────────────
/* REXX */
"ISREDIT MACRO"
"ISREDIT CHANGE 'ALICE.OLD' 'ALICE.NEW' ALL"
"ISREDIT (CT) = CHANGE_COUNTS"
"ISREDIT MSG = 'REPFX: changed' word(CT,1) 'lines'"
"ISREDIT END SAVE"
exit 0
Output:
REPFX: changed 38 lines
Run it across an entire PDS from option 3.4:
Line command: M REPFX (* member-list M command runs the macro *)
Output: (none — exits 0 on success, one line per member)
Column-mode renumber on JCL DD statements
Renumber sequential DD names — DD01, DD02, ..., DD50 — that drifted out of order after a refactor. Set BOUNDS to the DD-name columns, mark the source line containing the lowest correct value, then OO over the run.
Command ===> BOUNDS 4 7
CC 000100 //DD01 DD ...
CC 000100 //DD01 DD ...
OO 000200 //DDxx DD ...
OO 000999 //DDxx DD ...
Then C 'DD01' 'DD02' to bump sequentially, or use a REXX macro that:
- reads each line
- extracts the trailing digits
- rewrites the line with the next number
Output: (none — exits 0 on success)
Strip sequence numbers on a copied PDS member
A team member sent you a JCL fragment with COBOL sequence numbers in columns 73-80 that confuse SUBMIT. Wipe them in three keystrokes.
Command ===> BOUNDS 73 80
Command ===> C P'=' ' ' ALL
Command ===> BOUNDS
Output:
CHARS '=' (picture) changed 547 times.
BOUNDS SET TO 1 80.
Bulk-comment a block of REXX
Add /* ... */ to a marked block so you can test a code path without deleting it. The shifting commands > and < keep the leading characters intact.
000100 say 'before block'
)) 000101 if cond1 then
000102 do
000103 call sub
000104 end
)) 000110 say 'after block' (* )) marks block end — shifts 1 column right*)
Now overtype the new leading column with *:
Command ===> X ALL
Command ===> F P'>' FIRST 1 1
Command ===> RESET
Command ===> C 'D ' '/*' 1 2 ALL .S .E (* targeted column replace *)
Output: (none — exits 0 on success)
Diff two members in a split-screen
Open the source member in Edit on screen 1; press PF2 to split; on screen 2 open the comparison member; toggle PF9 to swap. To merge a hunk from screen 2 to screen 1, label the lines on screen 2 with .S and .E, then CREATE to a scratch dataset and COPY into the target line.
PF2 (* split horizontally at cursor row *)
=2 (* on the new screen go to Edit *)
EDIT 'ALICE.JCL.LIB(ALICEJ01)' (* second member *)
PF9 (* swap focus *)
Output: (none — opens a second logical screen)
Find unprintable bytes in a copied dataset
A binary that should have been EBCDIC contains a few stray ASCII bytes (CR X'0D', LF X'0A'). Locate them precisely with hex search and let the cursor land on the offender.
Command ===> HEX ON
Command ===> X ALL
Command ===> F X'0D' ALL FIRST
Output:
CHARS X'0D' found 4 times.
Inspect each match in turn with PF5 (RFIND), and use the prefix D line command to delete the bad records.
Build a one-shot ISREDIT macro from inside Edit
You need a quick macro but do not want to allocate a new EXEC. Open a temporary dataset, write the REXX, save, run, throw away.
EDIT 'ALICE.EXEC(SCRATCH)'
... write the REXX ...
SAVE
END (* save and return *)
=2 (* back into the dataset you want to edit *)
Command ===> SCRATCH (* invokes ALICE.EXEC(SCRATCH) as a macro *)
Output: (none — exits 0 on success)
Macro: append today's date to every line containing "VERSION"
Combines ISREDIT FIND with DATE() REXX builtin to stamp each match with the current date.
/* REXX */
"ISREDIT MACRO"
TODAY = DATE("S") /* YYYYMMDD */
"ISREDIT (LAST) = LINENUM .ZL"
do i = 1 to LAST
"ISREDIT (LINE) = LINE " i
if pos("VERSION", LINE) > 0 then do
NEW = strip(LINE) " " TODAY
"ISREDIT LINE " i " = (NEW)"
end
end
"ISREDIT MSG = 'Stamped lines with' TODAY"
exit 0
Output:
Stamped lines with 20260525
Macro: indent every nested block under "PROCEDURE DIVISION"
Walks every line below the first PROCEDURE DIVISION header and shifts code 2 columns right — a quick COBOL re-indent without leaving Edit.
/* REXX */
"ISREDIT MACRO"
"ISREDIT FIND 'PROCEDURE DIVISION' FIRST"
"ISREDIT (ROW) = CURSOR"
"ISREDIT (LAST) = LINENUM .ZL"
do i = ROW + 1 to LAST
"ISREDIT (LINE) = LINE " i
"ISREDIT LINE " i " = ' ' || LINE"
end
"ISREDIT MSG = 'Indented body of PROCEDURE DIVISION'"
exit 0
Output: (none — exits 0 on success)
Combine SORT and EXCLUDE for an ad-hoc report
You have a 50,000-line trace and want to see only the lines tagged WARNING or ERROR, sorted by timestamp in columns 1-10.
Command ===> X ALL
Command ===> F P'@@@@@@@' ALL 17 23 (* show rows whose cols 17-23 are alpha *)
Command ===> RESET FIND
Command ===> X 'INFO' ALL (* now exclude noise *)
Command ===> SORT 1 10 A
Output:
73 LINE(S) NOT DISPLAYED.
SORT successful.