code documentation - software development - COBOL -

COBOL Tutorial: Build and Run a File-Processing Program

A hands-on COBOL tutorial for modern developers: understand the four divisions, compile with GnuCOBOL, process a sequential file, and check file status.

Written by DocuWriter.ai Reviewed by DocuWriter Editorial Team on September 7, 2026

This COBOL tutorial builds one small batch program from start to finish. The program opens a sequential customer file, reads fixed-width records, displays each customer, checks the file status after operations, and closes the file.

You can compile the example with GnuCOBOL on a local computer. Production COBOL environments vary, especially on IBM mainframes, so use the compiler and file-assignment conventions for the system you maintain.

What the COBOL computer language is designed to do

COBOL code used for business data processing

COBOL stands for Common Business-Oriented Language. Its syntax and data model are built for business records, decimal arithmetic, reports, and batch processing. You will often encounter it in systems where exact field layouts and predictable file operations matter more than compact syntax.

A COBOL program is organized into four divisions:

DivisionPurpose in this tutorial
IDENTIFICATION DIVISIONNames the program
ENVIRONMENT DIVISIONMaps the logical customer file to a physical file
DATA DIVISIONDefines the file record, status fields, and end-of-file flag
PROCEDURE DIVISIONOpens, reads, displays, and closes the file

This structure is verbose, but it lets a maintainer locate file configuration, record layouts, and executable logic without guessing.

Set up GnuCOBOL

GnuCOBOL is an open-source COBOL compiler suitable for this local tutorial. Install it using the package instructions for your operating system, then confirm the compiler is available:

cobc --version

Create a working directory with two files:

cobol-tutorial/
├── customers.dat
└── customer-report.cbl

The sample uses free source format. Compiler defaults and available language features differ by version, so the compile command explicitly selects that format.

Create the fixed-width input file

Add these lines to customers.dat:

00001Ada Lovelace                  +000125050
00002Grace Hopper                  -000004250
00003Annie Easley                  +000980000

Each line is 45 characters:

  • customer ID: 5 numeric characters;
  • customer name: 30 characters, padded with spaces;
  • balance: 10 characters containing a separate leading sign and nine digits, with two implied decimal places.

COBOL reads by position. If a field is one character too short, every field after it can be misread. Fixed-width samples are worth checking in an editor that can show column numbers.

Write the COBOL program

Add the following to customer-report.cbl:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CUSTOMER-REPORT.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT CUSTOMER-FILE
               ASSIGN TO "customers.dat"
               ORGANIZATION IS LINE SEQUENTIAL
               FILE STATUS IS WS-FILE-STATUS.

       DATA DIVISION.
       FILE SECTION.
       FD  CUSTOMER-FILE.
       01  CUSTOMER-RECORD.
           05 CUSTOMER-ID       PIC 9(5).
           05 CUSTOMER-NAME     PIC X(30).
           05 CUSTOMER-BALANCE  PIC S9(7)V99 SIGN IS LEADING SEPARATE.

       WORKING-STORAGE SECTION.
       01  WS-FILE-STATUS       PIC XX VALUE SPACES.
       01  WS-END-OF-FILE       PIC X VALUE "N".
           88 END-OF-FILE       VALUE "Y".

       PROCEDURE DIVISION.
       MAIN.
           OPEN INPUT CUSTOMER-FILE

           IF WS-FILE-STATUS NOT = "00"
               DISPLAY "OPEN FAILED, FILE STATUS " WS-FILE-STATUS
               STOP RUN
           END-IF

           PERFORM UNTIL END-OF-FILE
               READ CUSTOMER-FILE
                   AT END
                       SET END-OF-FILE TO TRUE
                   NOT AT END
                       DISPLAY CUSTOMER-ID " | "
                               CUSTOMER-NAME " | "
                               CUSTOMER-BALANCE
               END-READ

               IF WS-FILE-STATUS NOT = "00"
                  AND WS-FILE-STATUS NOT = "10"
                   DISPLAY "READ FAILED, FILE STATUS " WS-FILE-STATUS
                   SET END-OF-FILE TO TRUE
               END-IF
           END-PERFORM

           CLOSE CUSTOMER-FILE

           IF WS-FILE-STATUS NOT = "00"
               DISPLAY "CLOSE FAILED, FILE STATUS " WS-FILE-STATUS
           END-IF

           STOP RUN.

The program has no placeholder sections: you can compile it as written and inspect every part discussed below.

Compile and run the example

From the working directory, run:

cobc -x -free -Wall customer-report.cbl
./customer-report

On Windows, run the generated executable using the filename produced by your environment. A successful run prints three customer records. Exact spacing and numeric display can vary with compiler and locale configuration.

The flags used here are:

  • -x: build an executable program;
  • -free: parse free-format COBOL source;
  • -Wall: enable a broad set of compiler warnings.

Treat warnings as review work. Do not remove a warning flag just to obtain a quiet build.

Understand the file connection

The SELECT clause gives the program a logical file name:

SELECT CUSTOMER-FILE
    ASSIGN TO "customers.dat"
    ORGANIZATION IS LINE SEQUENTIAL
    FILE STATUS IS WS-FILE-STATUS.

ASSIGN TO maps that name to the file used by this local GnuCOBOL example. Mainframe environments commonly supply file assignments outside the program, so do not copy the local filename convention into production without checking the runtime configuration.

ORGANIZATION IS LINE SEQUENTIAL means records are separated by the platform’s line ending. Other file organizations, such as indexed and relative, support different access patterns and require different declarations.

Read the record definition

The FD entry describes one input record:

01  CUSTOMER-RECORD.
    05 CUSTOMER-ID       PIC 9(5).
    05 CUSTOMER-NAME     PIC X(30).
    05 CUSTOMER-BALANCE  PIC S9(7)V99 SIGN IS LEADING SEPARATE.

The PIC clauses specify the layout:

  • 9(5) accepts five numeric positions;
  • X(30) accepts 30 alphanumeric positions;
  • S9(7)V99 SIGN IS LEADING SEPARATE describes a value with one sign character, seven integer positions, and two implied decimal positions.

The V does not consume a character in the file. It tells COBOL where the program should interpret the decimal point.

Follow the OPEN, READ, and CLOSE lifecycle

The IBM Enterprise COBOL reference for OPEN defines four common modes:

  • INPUT permits reading;
  • OUTPUT creates or replaces output data, depending on the file and environment;
  • I-O permits supported read and write operations on the same file;
  • EXTEND positions supported files so new records can be added after existing records.

This tutorial on COBOL uses OPEN INPUT because it only reads customers.dat. IBM’s guidance also notes that a successful OPEN is required before most file input/output statements. Although this example runs under GnuCOBOL, the explicit open-process-close lifecycle is portable COBOL thinking.

The READ statement has two branches:

READ CUSTOMER-FILE
    AT END
        SET END-OF-FILE TO TRUE
    NOT AT END
        DISPLAY CUSTOMER-ID
END-READ

File status 10 commonly represents end of file for a sequential read. The program allows 00 for success and 10 for normal completion, while reporting any other status.

Why file status belongs in the example

A tutorial that shows only the happy path teaches unsafe habits. A missing input file, incompatible file attributes, or invalid operation should produce a visible result instead of silently continuing.

The two-character WS-FILE-STATUS field changes after file operations. Interpret the exact code using the documentation for your compiler and runtime. On IBM systems, for example, file availability and attribute mismatches can produce different status values depending on organization and optional-file configuration.

In production code, centralize status handling when several files share the same policy, and include the logical file name and operation in any diagnostic output.

Extend this COBOL tutorial

Once the reader program works, make one change at a time:

  1. Count the number of records and display the count after CLOSE.
  2. Add an output file and write only customers with positive balances.
  3. Reject a record whose numeric fields do not match the expected layout.
  4. Replace line-sequential input with the file organization used by the system you maintain.
  5. Add a test fixture with an empty file and verify the end-of-file path.

When you move from a small example to an existing application, start by documenting the program divisions, copybooks, file layouts, called programs, job-control inputs, and external data stores. A COBOL documentation generator can provide a structured starting point, but a maintainer still needs to verify runtime assignments and business rules that are not explicit in the source.

For a broader modernization path, see how to understand legacy COBOL code. This tutorial on COBOL gives you the small, runnable baseline you need before tracing a larger batch job.