List all files in an IFS Folder with QSHELL

You can use Qshell to list IFS files in a CL program on an IBM i system (this exact technique works on the older iSERIES and AS400 systems in the exact same way).

Here's a basic example of how you can achieve this:

  • Create a CL program that uses Qshell to list the files in a specific directory.
  • Redirect the output of the Qshell command to a file in the QTEMP library.
  • Read the file in the CL program to process the list of files.

Here's a sample CL program:

PGM
DCLF FILE(QTEMP/FILELIST)
MONMSG MSGID(CPF0000)

/* Create a temporary file to store the list of files */
CRTPF FILE(QTEMP/FILELIST) RCDLEN(1000)

/* Use Qshell to list the files and redirect the output to the temporary file */
QSH CMD('ls /path/to/your/ifs/directory > /qsys.lib/qtemp.lib/filelist.file')

/* Read the file and process each entry */
OVRDBF FILE(FILELIST) TOFILE(QTEMP/FILELIST)
RCVF
DOLOOP: IF COND(&EOF *EQ '0') THEN(DO)
/* Process each file */
/* Your processing logic here */
RCVF
ENDDO

/* Clean up */
DLTOVR FILE(FILELIST)
DLTF FILE(QTEMP/FILELIST)

ENDPGM

In this example:

  • The QSH CMD command lists the files in the specified IFS directory and redirects the output to a file in the QTEMP library.
  • The RCVF command reads each record from the file, allowing you to process each file name as needed.

In this example:

Example IBM i CLLE Program

This code snippet will override the response from QSHELL (STDOUT) direct into a file in QTEMP so we can read it. It will position itself into the folder that is being read. Use QSHELL to list the files - the response will be sent to our file. Then we read the file and do whatever magic we want with the files:

CMD - READ_DIR

CMD PROMPT('Process files in IFS')

PARM KWD(DIR) TYPE(CHAR) LEN(255) EXPR(YES) PROMPT('IFS Folder Name ie: /home/bob')

PARM KWD(FILTER) TYPE(CHAR) LEN(30) DFT('.') EXPR(YES) PROMPT('Filter files (ie: *.CSV)')

CLLE - READ_DIR

/* READ_DIR - Read all CSV files in a given IFS dir and process them */
/* Program : READ_DIR */
/* Author : nick litten */
/* Function: List selected files in an IFS DIR using QSHELL. */
/* Read that file and do some stuff with the files that are listed */
/* Compile Instructions.. 1: CRTPF FILE(QTEMP/READ_DIRF) RCDLEN(1000)*/ /* 2: CRTBNDCL PGM('library'/READ_DIR) */
/* SRCFILE('library'/QCLLESRC) */
/* SRCMBR(READ_DIR) */
/* REPLACE(*YES) */

PGM PARM(&DIR &FILTER)
COPYRIGHT TEXT('READ_DIR Ver.000')
DCLF FILE(READ_DIRF) OPNID(FILE)
DCL VAR(&DIR) TYPE(CHAR) LEN(255)
DCL VAR(&FILTER) TYPE(CHAR) LEN(30)
DCL VAR(&PREVPATH) TYPE(CHAR) LEN(1024)
DCL VAR(&PPATHLEN) TYPE(DEC) LEN(7 0)
DCL VAR(&QSHSTRING) TYPE(*CHAR) LEN(1024)
DCL VAR(&CNLSTS) TYPE(CHAR) LEN(1) VALUE('0')
DCL VAR(&CRASHED) TYPE(LGL) VALUE('0')
DCL VAR(&MSGID) TYPE(CHAR) LEN(7)
DCL VAR(&MSGDTA) TYPE(CHAR) LEN(256)
DCL VAR(&MSGFIL) TYPE(CHAR) LEN(10)
DCL VAR(&MSGFLIB) TYPE(CHAR) LEN(10)
DCL VAR(&MSGKEY) TYPE(CHAR) LEN(4)
DCL VAR(&RTNTYPE) TYPE(CHAR) LEN(2)
DCL VAR(&SENDER) TYPE(*CHAR) LEN(80)

MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(CRASH)) /* Global monitor to pick non monitored error conditions */

/* Validate the directory name */
CHKLNK OBJ(&DIR)
MONMSG MSGID(CPF0000) EXEC(DO)
 SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG)
  MSGDTA(' Directory' *BCAT &DIR *TCAT ' not found')
  TOPGMQ(PRV) MSGTYPE(ESCAPE)
ENDDO

/* collect the current directory we are pointed at - we will revert to this when we finish */

RTVCURDIR RTNDIR(&PREVPATH) DIRNAMLEN(&PPATHLEN)

CD DIR(&DIR)
MONMSG MSGID(CPFA09C) EXEC(DO)
 SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG)
  MSGDTA('* Not authorised to directory' BCAT &DIR)
  TOPGMQ(PRV) MSGTYPE(*ESCAPE)
ENDDO

/* create a work file to hold the list of files that we load from the IFS directory */

DLTF FILE(QTEMP/READ_DIRF)
MONMSG MSGID(CPF0000)

CRTPF FILE(QTEMP/READ_DIRF) RCDLEN(1000)

/* load the work file with a list of all the selected files in the IFS directory */

OVRDBF FILE(STDOUT) TOFILE(QTEMP/READ_DIRF) OVRSCOPE(JOB)

CHGVAR VAR(&QSHSTRING) VALUE('ls' *BCAT &DIR *TCAT '/' *TCAT &FILTER *TCAT ' -a | sort')

QSH CMD(&QSHSTRING)

DLTOVR FILE(STDOUT) LVL(*JOB)

IF COND(&PPATHLEN *GT 0) THEN(CD DIR(&PREVPATH))

 OVRDBF FILE(READ_DIRF) TOFILE(QTEMP/READ_DIRF)
 POSITION(START) OVRSCOPE(CALLLVL)

/* read the list of files from the IFS folder we listed */
DOWHILE COND(&CNLSTS = '0')

 RCVF OPNID(FILE)

 MONMSG MSGID(CPF0864) EXEC(LEAVE)

 /* field &READ_DIRF is the file name ie: something.csv */
 SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG)
  MSGDTA('-- Doing something with' *BCAT &FILE_READ_DIRF)
  TOPGMQ(*PRV) MSGTYPE(*COMP)

 /* Add your logic here to do the IFS FILE magic */
 RTVJOBA ENDSTS(&CNLSTS)

ENDDO

DLTOVR FILE(READ_DIRF) LVL(*)

SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Directory' *BCAT &DIR *TCAT ' has been read and files(' *TCAT &FILTER *TCAT ') have been processed') TOPGMQ(PRV) MSGTYPE(COMP)

RETURN

/* CRASH : Routine to handle unexpected errors */
CRASH:
IF COND(&CRASHED) THEN(RETURN)
CHGVAR VAR(&CRASHED) VALUE('1')
RCVMSG MSGTYPE(*LAST) MSGDTA(&MSGDTA) MSGID(&MSGID) RTNTYPE(&RTNTYPE) MSGF(&MSGFIL) SNDMSGFLIB(&MSGFLIB)
IF COND(&RTNTYPE *EQ '15' *OR &RTNTYPE *EQ '17') THEN(DO)
 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFIL) MSGDTA(&MSGDTA) MSGTYPE(*DIAG)
ENDDO

ESCAPE:
IF COND(&PPATHLEN *GT 0) THEN(DO)
 CD DIR(&PREVPATH)
 MONMSG MSGID(CPF0000)
ENDDO
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('* Program READ_DIR ended abnormally') MSGTYPE(*ESCAPE)
RETURN
ENDPGM: ENDPGM

I know I know.... That program just sort of grew as I put in my ear buds (not those poncy apple air pods) and got some programming grooove on.

When this runs it looks something like this:

IFS LIST - how-to-get-a-list-of-all-files-in-an-ifs-folder

Easy huh?

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>