How can I run my Rexx program as a batch job?

2019-03-06 03:05发布

问题:

I have a Rexx program that I want to run as a batch job. How can I do this?

This is my program :-

/* Rexx – HELLO – Write Hello World */
Say "hello World"

The program is located as member HELLO in the PDS ME.USER.EXEC.

A valid JOB CARD for my installation is (our environment includes ISPF/PDF as opposed to ROSCOE):-

//MYJOB    JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID

Note! this has been written as a tutorial

回答1:

There are a number of ways that you can run the program via batch. I will cover 3 ways all of which are different according to the environment (i.e. what they can utilise.)



Method 1 - Run the program in a Rexx environment.

This entails running the program IRXJCL and passing the name of the program (i.e. the PDS's member name) via the PARM field (you can also pass parameters; accessing them via a PARSE ARG statement).

IRXJCL requires (normally) 3 DDNAMES they are SYSEXEC (The PDS where the program is located), SYSTSIN (this can reflect terminal input) and SYSTSPRT (this is where terminal output is sent).

Here is the JCL that would work according the information provided above:-

//MYJOB    JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID
//*-------------------------------------------------------------------
//RUNPROG  EXEC PGM=IRXJCL,PARM=’HELLO’
//*
//*        RUN OUR REXX PROGRAM CALLED HELLO
//*
//SYSEXEC  DD DSN=ME.USER.EXEC,DISP=SHR
//SYSTSIN  DD DUMMY
//SYSTSPRT DD SYSOUT=*
//*-------------------------------------------------------------------

This method, although the simplest (by just a few lines of JCL), is the most restrictive in that it does not allow the use of TSO/E services, such as TSO/E commands and most of the TSO/E external functions.

However, as IRXJCL is a Rexx processor, there is no requirement to let TSO/E know that it is a Rexx program (the first line must include REXX).



Method 2 - Run the program from a TSO/E environment

This entails running one of the TSO/E batch processing programs IKJEFT01 is used in this example. Alternatives are IKJEFT1A and IKJEFT1B. TSO/E services and commands can be used via this method (e.g. note at end of this method using the TIME command)

Comprehensive information about the differences between the programs can be found at Writing JCL for command execution

The JCL for IKJEFT01 is similar to that used in Method 1. An additional DDNAME SYSPROC can be coded. SYSPROC is the DDNAME where CLISTS would be located; You can have Rexx programs found here in addition to SYSEXEC (which isn't required, a suggestion is that both are coded and that SYSEXEC is used for Rexx programs and SYSPROC is used for CLISTS).

It's the requirement that Rexx is on the first line that differentiates a Rexx program from a CLIST (by the TSO/E processor). Thus, if the Rexx program is found/located via SYSEXEC, if I recall correctly, this negates the requirement).

Another suggestion is to always include REXX in the first line of a Rexx program>

The EXEC statement invokes the IKJEFT01 program instead of IRXJCL. PARM can be used to specify the first command (and therefore our HELLO program). However, as for foreground, you can specify this via the terminal i.e. the SYSTSIN DDNAME.

Here is some JCL that would work for the second method; noting that the HELLO program is invoked via the SYSTSIN DDNAME as instream data :-

//MYJOB    JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID
//*-------------------------------------------------------------------
//RUNPROG  EXEC PGM=IKJEFT01
//*
//*        RUN OUR REXX PROGRAM CALLED HELLO IN A TSO/E ENVIRONMENT
//*
//SYSPROC  DD DSN=ME.USER.CLIST,DISP=SHR
//SYSEXEC  DD DSN=ME.USER.EXEC,DISP=SHR
//SYSTSIN  DD *
 HELLO
//SYSTSPRT DD SYSOUT=*
//*-------------------------------------------------------------------

If, for example, the following were used (i.e. added TIME as another line to SYSTSIN) then the TSO/E TIME command would be run (which would cause the time to be displayed to SYSTSPRT).

//SYSTSIN  DD *
     HELLO
     TIME


Method 3 - Run the program in an ISPF environment

This method uses the IKJEFT01 program (see method 2 for IKJEFT1A/B alternatives). However, it then uses the ISPSTART command to run the program in an ISPF environment; enabling the use of ISPF services (e.g file tailoring (skeletons) ISPF tables etc).

An ISPF environment has additional requirements in that ISPF libraries need to be allocated in order to start an ISPF environment. At a minimum have the supplied ISPF libraries allocated to ddnames ISPPLIB (ISPF Panels), ISPMLIB (ISPF Messages) & ISPTLIB (ISPF Tables). ISPPROF is where ISPF keeps some profile data for the session, so a temporary store is sufficient (UNIT=SYSDA is often available if not always).

Note you would likely allocate, at a minimum, the installations system libraries (the TSO/E command LISTA can likely be used to determine these from a foreground session). Alternately, ask you local friendly system programmers. In the following they are SYS1.ISPPLIB, SYS1.ISPMLIB and SYS1.ISPTLIB.

Here is some JCL that would work for the 3rd method. Note that HELLO is passed as a parameter to the ISPSTART command.

//MYJOB    JOB ,,CLASS=1,MSGCLASS=H,NOTIFY=&SYSUID
//*-------------------------------------------------------------------
//RUNPROG  EXEC PGM=IKJEFT01
//*
//*        RUN OUR REXX PROGRAM HELLO IN A TSO/E/ISPF ENVIRONMENT
//*
//SYSPROC  DD DSN=ME.USER.CLIST,DISP=SHR
//SYSEXEC  DD DSN=ME.USER.EXEC,DISP=SHR
//ISPPLIB  DD DSN=SYS1.ISPPLIB,DISP=SHR
//ISPMLIB  DD DSN=SYS1.ISPMLIB,DISP=SHR
//ISPTLIB  DD DSN=SYS1.ISPTLIB,DISP=SHR
//ISPPROF  DD UNIT=SYSDA,SPACE=(CYL,(10,1)),
//            RECFM=FB,LRECL=80,BLKSIZE=0
//SYSTSIN  DD *
 ISPSTART CMD(HELLO)
//SYSTSPRT DD SYSOUT=*
//*-------------------------------------------------------------------

Note this is not a fully comprehensive, it is an overview that should suffice for getting started with running Rexx programs in batch.



回答2:

Additional comments to the above answer.. The below technote may be helpful if you wish to run your REXX exec using ISPF services...

http://www.ibm.com/support/docview.wss?uid=swg21023990

Make sure that the ISPPROF file is concatenated as the first file in ISPTLIB. The example uses a temporary file that will be unique to the job. If the REXX exec does table services you may need an ISPTABL DD. I would suggest using the same file for ISPPROF and ISPTABL and concatenate it first in ISPTLIB. This can be a permanent file if the table needs to be save, however it should not be in use by other jobs or TSO users so as to avoid enqueue errors.

As the previous update stated his answers suffice for the simple REXX exec.



回答3:

Yet more additional comments to the answer by MikeT...

Suppose you want your JCL to be self-contained: you want to include a REXX exec as an in-stream data set in the JCL, rather than referring to a REXX exec stored in a PDS member.

Here's the "trick" (for IRXJCL; I haven't tested this trick with other programs): specify a single null (X'00') byte as the value of the PARM attribute of the EXEC statement.

To specify the null byte, use the z/OS ISPF editor with HEX ON:

//REXX     EXEC PGM=IRXJCL,PARM=' '
66DCEE44444CECC4DCD7CDEDCD6DCDD7707
1195770000057530774E997133B7194ED0D

For example, if you entered PARM=' ' with a space as the value, overtype the 4 of the hex value of that space with a 0.

Here's an example job step containing an in-stream REXX exec that processes the output from a previous step in the same job:

//* PARM value is a single X'00' byte                          
//REXX     EXEC PGM=IRXJCL,PARM=' '                            
//SYSEXEC  DD   DATA,DLM=$$                                    
/*                                                             
   Transposes first line of input CSV into one record per field
   Reads CSV from ddname SYSTSIN.                              

   Writes output to ddname SYSTSPRT.                           
*/                                                             
columnSeparator = ","                                          

/* Get the header row */                                       
parse pull row                                                 
/* Get column names */                                         
do i = 1 until row = ""                                        
  parse value row with columnName "," row                      
  say columnName                                               
end                                                            
exit 0                           
$$                               
//SYSTSIN  DD  DSN=&&CSV,DISP=OLD
//SYSTSPRT DD  SYSOUT=*          

Notes:

  • In this context, the first line of the REXX exec does not need to contain the string "REXX"
  • DLM=$$ enables you to use REXX comment syntax (/*) without prematurely ending the in-stream data set
  • &&CSV refers to a CSV file created by a previous job step (not shown)

I use this "in-stream REXX" technique mostly for ad hoc execs to transform the output of a batch program into what I really want. This technique can be useful for demonstrations and quickly bouncing ideas around; other developers can view the REXX code in situ in the JCL in SDSF output, tweak it, and then submit the tweaked version.