View previous topic :: View next topic
|
Author |
Message |
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
Good morning,
I would have a problem to submit.
I have a member of a PDS-E library that contains a large list of dataset names, I would like to be able to dynamically create, in the same PDS-E libraries, output members that contain 5 datasets each.
I want to create everything with a REXX, and not use Sort or Icetool.
The Rexx I created works, but it creates 1 member for each line read from the Input file, so it creates me 15 Run, I would like to be able to create 3 Runs from 5 datasets each.
Below I attach the input member with 15 dataset name: INP
Of course I also attach the Rexx I created.
Thanks for any support
Member used as INPUT in the PDS-E library: INP
Code: |
***************************** Top of Data ******************************
XA1MVS.REC.D12214.DOC.001
XB1MPS.REC.D12214.DOC.002
XC1MVS.REC.D12214.DOC.003
XD1MVS.REC.D12214.DOC.004
XE1MVS.REC.D12214.DOC.005
XF1MVS.REC.D12214.DOC.006
XG1MVS.REC.D12214.DOC.007
XH1MVS.REC.D12214.DOC.008
XI1MVS.REC.D12214.DOC.009
XL1MVS.REC.D12214.DOC.010
XM1MVS.REC.D12214.DOC.011
XN1MVS.REC.D12214.DOC.012
XO1MVS.REC.D12214.DOC.013
XP1MVS.REC.D12214.DOC.014
XQ1MVS.REC.D12214.DOC.015
**************************** Bottom of Data ****************************
|
REXX, attention to try it, the INPUT and OUTPUT must be replaced:
Code: |
inpdset = 'name.pdse ('Inp')'
outdset = 'name.pdse'
|
Full REXX:
Code: |
/* REXX -----------------------------------------------------------*\
\*------------------------------------------------------------------*/
inpdset = 'name.pdse('Inp')'
outdset = 'name.pdse'
count = 1
temp = 1
"ALLOC DDN(INFILE) DSN('"inpdset"') SHR"
"EXECIO * DISKR INFILE(STEM Record. FINIS)"
"FREE DDN(INFILE)"
/*-------------------------------------------------------------------*/
Do RowX=1 to Record.0
Load_Rec = Record.0
Out.Temp = Record.RowX
NextRow = RowX + 1
NextRecd = Record.NextRow
Dsname = Word(NextRecd,1)
If Dsname ^= '' and NextRow <= 5 then
Do
OutDS = outdset!!'('!!'Run'!!count!!')'
OutDS = strip(OutDS)
say 'OutDS----->' OutDS
/*---------------------------------------------*/
"ALLOC DDN(OFILE) DSN('"OutDS"')NEW ",
"LIKE('"inpdset"')"
"FREE DDN(OFILE)"
"ALLOC DDN(OFILE) DSN('"OutDS"') SHR"
"EXECIO * DISKW OFILE(STEM OUT. FINIS)"
"FREE DDN(OFILE)"
Drop Out.
Temp = 0
Count = Count + 1
/*---------------------------------------------*/
End
Temp = Temp + 1
End
say 'End Process'
Exit
/*---------------------------------------------------------------*/
|
|
|
Back to top |
|
|
Nic Clouston
Global Moderator
Joined: 10 May 2007 Posts: 2455 Location: Hampshire, UK
|
|
|
|
Why do you write out when your counter is <= 5? You surely want it to write out when you have reached 5. |
|
Back to top |
|
|
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
Hi Nic,
you're right, I tried so many versions that I probably missed the typing error.
Sorry |
|
Back to top |
|
|
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
My wish would be to get to this:
Member into Library:
Code: |
Command ===>
Name Prompt Size Created
_________ INP 15 2019/09/17
_________ RUN1 5 2019/09/17
_________ RUN2 5 2019/09/17
_________ RUN3 5 2019/09/17
**End**
|
Member: RUN1
Code: |
***************************** Top of Data *
XA1MVS.REC.D12214.DOC.001
XB1MPS.REC.D12214.DOC.002
XC1MVS.REC.D12214.DOC.003
XD1MVS.REC.D12214.DOC.004
XE1MVS.REC.D12214.DOC.005
**************************** Bottom of Data
|
Member: RUN2
Code: |
***************************** Top of Data *
XF1MVS.REC.D12214.DOC.006
XG1MVS.REC.D12214.DOC.007
XH1MVS.REC.D12214.DOC.008
XI1MVS.REC.D12214.DOC.009
XL1MVS.REC.D12214.DOC.010
**************************** Bottom of Data
|
Member: RUN3
Code: |
***************************** Top of Data *
XM1MVS.REC.D12214.DOC.011
XN1MVS.REC.D12214.DOC.012
XO1MVS.REC.D12214.DOC.013
XP1MVS.REC.D12214.DOC.014
XQ1MVS.REC.D12214.DOC.015
**************************** Bottom of Data
|
|
|
Back to top |
|
|
Willy Jensen
Active Member
Joined: 01 Sep 2015 Posts: 712 Location: Denmark
|
|
|
|
I will suggest a slightly different approach, using the stack and using BPXWDYN for allocate and free:
Code: |
lib='xx.test.lib'
cc=bpxwdyn('alloc da('lib'(zdslist)) shr rtddn(dd1)')
"execio * diskr" dd1 "(stem dsl. finis)"
cc=bpxwdyn('free dd('dd1')')
"newstack"
outn=0
do dsn=1 to dsl.0
queue dsl.dsn
if queued()//5=0 then call write /* recno divisible by 5 */
end
if queued()>0 then call write
cc=bpxwdyn('free dd('dd1')')
"delstack"
exit 0
Write:
outn=outn+1
say 'new ds' outn 'at record' dsn 'will contain' queued() 'records'
cc=bpxwdyn('alloc da('lib'(run'outn')) shr dd('dd1') reuse')
"execio" queued() "diskw" dd1 "(finis)"
return 0 |
I understood it so that the new members are written to the same library as the datasetlist. |
|
Back to top |
|
|
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
Hi Willy, the method you proposed is fantastic, it works very well.
I had never tried the bpxwdyn method, so thank you for making me new methods.
How can I put [Solved] in this discussion?
Thanks again Willy for the support. |
|
Back to top |
|
|
Willy Jensen
Active Member
Joined: 01 Sep 2015 Posts: 712 Location: Denmark
|
|
|
|
You are welcome. I prefer the BPXWDYN command to ALLOC as it has some very usefull features, plus it is a function so can be placed in an expression.
BPXWDYN is described in the 'Using REXX and z/OS UNIX System Services' manual.
I dont think that you can 'solve' a discussion, but your latest entry should make it clear. |
|
Back to top |
|
|
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
Hi Willy thanks for the explanations.
I have already downloaded the 'Using REXX and z / OS UNIX System Services' manual.
Thanks again Willy for the support. |
|
Back to top |
|
|
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
Thanks to the help and support of Willy I managed to complete REXX as I wanted.
I make it available to everyone if it can be used by some other user.
REXX can also be modified to launch other HSM commands, such as Recall, Recover, Migration.
Kind regards
Ghellar
Code: |
/* REXX ______________________________________________________________
| |
| This REXX takes INPUT a member of a Library in which it is |
| a List of Datasets has been inserted (taken from a query). |
| The dataset names MUST be in column 1, these DSNAMEs are read |
| one by one and a Backup Delete HSM command will be created: |
| |
| Queue ' HSEND BDELETE ('!!DsName!!') ALL' |
| |
| These command lists will then be dynamically saved to a series |
| of members (in the same library where the member of INPUT), with |
| names chosen a priori before launching the REXX. |
| There are indeed variables that necessarily go valued before |
| ANY LAUNCH, and are reported by following: |
| | | | | | |
| V V V V V |
|____________________________________________________________________*/
/*-------------------------------------------------------------------*/
/*Preparatory variables to be modified by hand before EEXEC launch */
/*-------------------------------------------------------------------*/
InpLib = pds.library.name /* Extended name of the library */
ZDSLIST = INP /* Member of INPUT in the library */
NameRun = RUN$ /* Partial name member: OUTPUT */
N$Split = 5 /* Number DSN that will be split */
/*********************************************************************/
/*-------------------------------------------------------------------*/
CC=BPXWDYN('ALLOC DA('InpLib'('ZDSLIST')) SHR RTDDN(DD1)')
"EXECIO * DISKR" DD1 "(STEM DSL. FINIS)"
CC=BPXWDYN('FREE DD('DD1')')
/*-------------------------------------------------------------------*/
"newstack" /* */
Outn=0 /* Clear the variable OutNumber */
JobN=0 /* Clear the variable: JobNumber */
/*--------------------------------*/
do dsn=1 to dsl.0 /* */
DsnName = WORD(DSL.dsn,1) /* */
QUEUE ' HSEND BDELETE ('!!DsnName!!') ALL'
if queued()//N_Split=0 then call Write
end /* */
if queued()>0 then call write /* */
cc=bpxwdyn('free dd('dd1')') /* */
"delstack" /* */
exit 0 /* */
/*-------------------------------------------------------------------*/
/* --- Start call Write -------------------------------------- */
/*-------------------------------------------------------------------*/
Write:
Outn=Outn+1 /*Add +1 to the OutNumber variable*/
Jobn=Jobn+1 /*Add +1 to the JobNumber variable*/
say 'new ds' Outn 'at record' dsn 'will contain' queued() 'records'
CC=BPXWDYN('ALLOC DA('InpLib'('NameRun''Outn')) SHR DD('DD1') REUSE')
call JobCard /* CALL JobCard insert jcl card */
"EXECIO" QUEUED() "DISKW" DD1 "(FINIS)"
Return 0
/*-------------------------------------------------------------------*/
/* --- End call Write -------------------------------------- */
/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/
/* --- Start call JobCard -------------------------------------- */
/*-------------------------------------------------------------------*/
JobCard:
If Jobn>=1 or Jobn<=9 then /* */
do /* */
Jobn='0'!!Jobn /* */
end /* */
jcl.1='//TMPJCL'Jobn' JOB MSGCLASS=8,CLASS=E,NOTIFY=&SYSUID '
jcl.2='//*---------------------------------------------------------'!!,
'------------'
jcl.3='//* JOB that deletes ALL obsolete files with alias: xxxxxx '
jcl.4='//*---------------------------------------------------------'!!,
'------------'
jcl.5='//BKDELETE EXEC PGM=IKJEFT01,DYNAMNBR=20 '
jcl.6='//* ---------------- '
jcl.7='//SYSPRINT DD SYSOUT=* '
jcl.8='//SYSTSPRT DD SYSOUT=* '
jcl.9='//SYSTSIN DD * '
jcl.0=9
/* */
do n=jcl.0 to 1 by -1 /* */
push jcl.n /* */
end /* */
Return
/*-------------------------------------------------------------------*/
/*---- End call JobCard ---------------------------------------*/
/*-------------------------------------------------------------------*/
|
|
|
Back to top |
|
|
enrico-sorichetti
Superior Member
Joined: 14 Mar 2007 Posts: 10873 Location: italy
|
|
|
|
unfortunately the snippet posted is unreadable , too much clutter
the noise outsizes the info
do not over-comment
spaces are much much better than a bunch of "---...---"
space properly the lines for readability ( a blank line is better that an irrelevant comment, or a <comment box>
Code: |
Outn=Outn+1 /*Add +1 to the OutNumber variable*/ |
how does the comment help ??? do not comment the obvious |
|
Back to top |
|
|
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
Hi Enrico,
unfortunately I do not work all the days with the REXX, so I always comment on the projects being realized, because I might need to modify them after months or years, this explains the reason for the comments.
I will take your comment as a suggestion for future projects.
Many thanks |
|
Back to top |
|
|
sergeyken
Senior Member
Joined: 29 Apr 2008 Posts: 2022 Location: USA
|
|
|
|
Ghellar wrote: |
Hi Enrico,
unfortunately I do not work all the days with the REXX, so I always comment on the projects being realized, because I might need to modify them after months or years, this explains the reason for the comments.
I will take your comment as a suggestion for future projects.
Many thanks |
Enrico is absolutely right.
Comments must clarify some non-obvious ideas, but not just repeat obvious things in other words! It makes the code even less understandable, and impossible to read.
Code: |
A = A + 1 /* this REXX arithmetic statement is supposed to perform
very critical operation. It takes the previous value
of variable A, then performs arithmetic addition
with value of 1, and places the result back
to variable A.
Before any change to this code please, consult with
the author. */ |
Whenever I met comments of this style, my first desire was: how to kill the author?
Also endless use of '---------------------------------------------', or even '******************************' makes it much worse compared to simple blank lines. |
|
Back to top |
|
|
Willy Jensen
Active Member
Joined: 01 Sep 2015 Posts: 712 Location: Denmark
|
|
|
|
Guys, he got his problem solved and was kind enough to share his solution with us. He uses more comments than you (and I) like to, but that does not neccessarily make it wrong. I have been been accused of using too few comments and writing much too compact code. At the end of the day it works for him.
If in the future someone faces a similar issue they can copy the program, stripping away what they deem superflous. Still easier that starting from scratch.
Just my 2 cents. |
|
Back to top |
|
|
Ghellar
New User
Joined: 01 Sep 2005 Posts: 22
|
|
|
|
Goodmorning everyone,
thank you for your opinions, sorry but I'm not as expert as you, I'm here to try to learn that's all. If you were an expert you know here in this forum to help others, and instead I am here asking for help from all of you for my lack of knowledge.
But I wouldn't want to have created a problem with these excessive comments, so to try to fix it, I simply attach the code without comments.
Thanks again to everyone.
Code: |
/* REXX ______________________________________________________________
| |
| This REXX takes INPUT a member of a Library in which it is |
| a List of Datasets has been inserted (taken from a query). |
| The dataset names MUST be in column 1, these DSNAMEs are read |
| one by one and a Backup Delete HSM command will be created: |
| |
| Queue ' HSEND BDELETE ('!!DsName!!') ALL' |
| |
| These command lists will then be dynamically saved to a series |
| of members (in the same library where the member of INPUT), with |
| names chosen a priori before launching the REXX. |
| There are indeed variables that necessarily go valued before |
| ANY LAUNCH, and are reported by following: |
| | | | | | |
| V V V V V |
|____________________________________________________________________*/
InpLib = pds.library.name
ZDSLIST = INP
NameRun = RUN$
N$Split = 5
CC=BPXWDYN('ALLOC DA('InpLib'('ZDSLIST')) SHR RTDDN(DD1)')
"EXECIO * DISKR" DD1 "(STEM DSL. FINIS)"
CC=BPXWDYN('FREE DD('DD1')')
"newstack"
Outn=0
JobN=0
do dsn=1 to dsl.0
DsnName = WORD(DSL.dsn,1)
QUEUE ' HSEND BDELETE ('!!DsnName!!') ALL'
if queued()//N_Split=0 then call Write
end
if queued()>0 then call write
cc=bpxwdyn('free dd('dd1')')
"delstack"
exit 0
Write:
Outn=Outn+1
Jobn=Jobn+1
say 'new ds' Outn 'at record' dsn 'will contain' queued() 'records'
CC=BPXWDYN('ALLOC DA('InpLib'('NameRun''Outn')) SHR DD('DD1') REUSE')
call JobCard /* CALL JobCard insert jcl card */
"EXECIO" QUEUED() "DISKW" DD1 "(FINIS)"
Return 0
JobCard:
If Jobn>=1 or Jobn<=9 then
do
Jobn='0'!!Jobn
end
jcl.1='//TMPJCL'Jobn' JOB MSGCLASS=8,CLASS=E,NOTIFY=&SYSUID '
jcl.2='//*---------------------------------------------------------'!!,
'------------'
jcl.3='//* JOB that deletes ALL obsolete files with alias: xxxxxx '
jcl.4='//*---------------------------------------------------------'!!,
'------------'
jcl.5='//BKDELETE EXEC PGM=IKJEFT01,DYNAMNBR=20 '
jcl.6='//* ---------------- '
jcl.7='//SYSPRINT DD SYSOUT=* '
jcl.8='//SYSTSPRT DD SYSOUT=* '
jcl.9='//SYSTSIN DD * '
jcl.0=9
do n=jcl.0 to 1 by -1
push jcl.n
end
Return
|
|
|
Back to top |
|
|
enrico-sorichetti
Superior Member
Joined: 14 Mar 2007 Posts: 10873 Location: italy
|
|
|
|
Quote: |
But I wouldn't want to have created a problem with these excessive comments,
|
You have not created any problem...
I was just suggesting to keep things simple for better visual navigation of the sources |
|
Back to top |
|
|
|