FNAMES (file names) is the OUTFIL parameter that tells DFSORT which DD name(s) to use for that OUTFIL's output. Every OUTFIL that writes to a dataset must specify FNAMES= so the system knows where to send the records. You can give a single DD name (e.g. FNAMES=REPORT) for one output dataset, or a list of DD names (e.g. FNAMES=(OUT1,OUT2,OUT3)) to write the same record stream to multiple datasets—or to distribute records across them when combined with SPLITBY or SPLIT1R. Each name in FNAMES= must have a matching //ddname DD ... in your JCL; otherwise the step will fail with an allocation error. This page covers FNAMES syntax (single vs multiple names, parentheses), how it interacts with split options, JCL requirements, and common usage patterns.
FNAMES= links an OUTFIL to one or more output datasets by DD name. In z/OS, every dataset used in a job step is allocated via a DD (Data Definition) statement. The DD name is the symbol you use in the JCL (e.g. //OUT1 DD DSN=MY.DATA.OUT1,...). When DFSORT executes an OUTFIL, it writes records to the dataset(s) allocated to the DD name(s) you specify in FNAMES=. So FNAMES=OUT1 means "write this OUTFIL's output to whatever dataset is allocated to DD name OUT1." If you specify FNAMES=(OUT1,OUT2), the same output stream is written to both datasets—you get two identical copies (unless you also use a split option, which changes how records are distributed).
For a single output, code FNAMES=ddname. Parentheses are optional: FNAMES=REPORT and FNAMES=(REPORT) are equivalent. For multiple outputs, you must list the names. You can use parentheses: FNAMES=(OUT1,OUT2,OUT3), or on some systems a comma-separated list without parentheses: FNAMES=OUT1,OUT2,OUT3. The parentheses form is standard and avoids ambiguity when you have many names or other parameters on the same line.
| Form | Meaning | Example |
|---|---|---|
| FNAMES=ddname | Single output; write to this one DD | FNAMES=REPORT |
| FNAMES=(dd1,dd2,...) | Multiple outputs; same stream to each DD (or split by SPLITBY/SPLIT1R) | FNAMES=(OUT1,OUT2,OUT3) |
| FNAMES=dd1,dd2 (no parens) | Same as list: dd1 and dd2 both receive the same stream | FNAMES=OUT1,OUT2 |
For every name that appears in FNAMES=, your JCL must include a DD statement with that name. For example, if you code OUTFIL FNAMES=(FILE1,FILE2), you need:
12//FILE1 DD DSN=MY.OUT.FILE1,DISP=(NEW,CATLG),SPACE=(TRK,(10,5)),LRECL=80,RECFM=FB //FILE2 DD DSN=MY.OUT.FILE2,DISP=(NEW,CATLG),SPACE=(TRK,(10,5)),LRECL=80,RECFM=FB
The LRECL and RECFM should match the record length and format that the OUTFIL produces (full record or as built by BUILD=). If you omit a DD, the step will fail when DFSORT tries to open that output. So always define each FNAMES= name in the same step.
When you have one OUTFIL and one output file, use FNAMES=ddname. For example, to write a report to a dataset named via DD REPORT:
1OUTFIL FNAMES=REPORT,BUILD=(1,80,81:80X)
Every record that this OUTFIL selects (subject to INCLUDE/OMIT if any) is written to the dataset allocated to REPORT. This is the most common case: one OUTFIL, one DD, one output file.
When you specify FNAMES=(DD1,DD2,...,DDk) without SPLIT, SPLITBY, or SPLIT1R, the same record stream is written to every listed DD. So you get k identical copies. Use this when you need the same output in more than one place—for example, one copy for production and one for archive, or one for region East and one for region West with the same data. Example:
1OUTFIL FNAMES=(PROD,BACKUP),BUILD=(1,80)
Both PROD and BACKUP receive the same 80-byte records. You must define both //PROD and //BACKUP in JCL with appropriate DSN and space.
When you combine FNAMES=(OUT1,OUT2,OUT3) with SPLITBY=n, records are distributed in blocks of n across the files (first n to OUT1, next n to OUT2, next n to OUT3, then next n to OUT1, and so on). So the three datasets no longer get identical copies; they get different subsets in rotating blocks. With SPLIT1R=n, the first n records go to OUT1, the next n to OUT2, the next n to OUT3, and any remainder to OUT3—contiguous blocks per file. So the meaning of multiple FNAMES= names depends on whether you use a split option: without one, same stream to all; with SPLITBY or SPLIT1R, records are split by count across the list.
Multiple OUTFILs, each with its own FNAMES= (usually one name per OUTFIL), let you write different content to different files: different INCLUDE/OMIT, different BUILD, or SAVE on the last to catch the rest. One OUTFIL with FNAMES=(A,B,C) without a split option writes the same content to A, B, and C. So: use multiple OUTFILs when you want different data or format per file; use one OUTFIL with multiple FNAMES when you want identical copies or when you are using SPLITBY/SPLIT1R to distribute by count.
The record length written to each FNAMES= dataset is determined by the OUTFIL: either the full record (after INREC/OUTREC if present) or the length defined by BUILD= on that OUTFIL. All datasets in the same FNAMES= list receive the same record format and length. So set LRECL and RECFM on each DD to match (e.g. LRECL=80, RECFM=FB for 80-byte fixed blocked).
FNAMES is like writing the same letter to three friends. You put three addresses (OUT1, OUT2, OUT3) on the envelope list—that's FNAMES=(OUT1,OUT2,OUT3). The post office (DFSORT) sends one copy to each address. So all three get the same letter. If you use a special rule like "send the first 500 letters to friend 1, the next 500 to friend 2," that's SPLITBY or SPLIT1R—then they get different bundles instead of the same copy. The addresses (DD names) must be real: you have to define them in JCL or the post office won't know where to send the mail.
1. What does FNAMES= on an OUTFIL statement specify?
2. What is the effect of OUTFIL FNAMES=(COPY1,COPY2),BUILD=(1,80)?
3. When using FNAMES=(OUT1,OUT2,OUT3) with SPLITBY=500, how are records distributed?
4. You want one OUTFIL to write to a single report dataset. How do you code FNAMES?
5. What happens if you use FNAMES=OUT1 in OUTFIL but do not define //OUT1 in JCL?