During my daily work I often need to copy members from one PDS to another. The Partitioned data sets are always the same ones, just different members. I could use the ISPF Move/Copy Utility screens but it quickly gets tiresome to have to keep entering the data set and member information into the screens.
Since I’ve got my REXX library allocated to SYSPROC so that I can run execs from it directly using the TSO execname command on the ISPF command line I put together the following exec called COPYMBR to automate the process:
/* rexx */ /* exec to copy a member from one pds to another */ parse arg frommbr tombr '/' repl tombr = strip(tombr) upper repl if frommbr = '' then do say "Syntax is COPYMBR from_mbr [to_mbr] [/r]" say "Specify to_mbr name to rename the copied member" say "Specify /r to replace the member in the target PDS" return 0 end if tombr='' then tombr=frommbr if length(frommbr) > 8 then do say "Source member name greater than 8 chars" return 0 end if length(tombr) > 8 then do say "Target member name greater than 8 chars" return 0 end address ispexec "CONTROL ERRORS RETURN" indsn="'"userid()||".LOAD'" /* Source PDS */ outdsn="'"userid()||".LOAD2'" /* Target PDS */ "LMINIT DATAID(IN) DATASET("indsn") ENQ(SHR)" "LMINIT DATAID(OUT) DATASET("outdsn") ENQ(SHR)" opt='' if repl = 'R' then opt = "REPLACE' "LMCOPY FROMID("in") FROMMEM("frommbr") TODATAID("out") ", "TOMEM("tombr") "opt lastcc=rc ins='' if lastcc = 0 then nop else if lastcc=12 then do if frommbr <> tombr then ins = 'as '||tombr say frommbr' not copied'||ins say tombr' already exists on target library.' end else if lastcc=8 then do say frommbr' not found in source library.' end else do say 'rc from LMCOPY='lastcc end "LMFREE DATAID("in")" "LMFREE DATAID("out")" return 0
You can edit the lines marked “Source PDS” and “Target PDS” to specify any compatible load libraries. I just used my LOAD and LOAD2 libraries as an example.
The general syntax of the COPYMBR command on the ISPF command line is then:
TSO COPYMBR member_name [new_name] [/r]
member_name is the name of the member to copy from the source PDS
new_name is optional and is the new name to assign to the member on the target PDS. If not specified it defaults to the same name as the source member.
/r tells the exec to replace the member (or new member name if renaming) on the target PDS.
Note that when the copy is successful, the exec does NOT output any messages so there’s no need to press the enter key to clear a message except when there is something wrong.
TSO COPYMBR MYPROG1 /r
Copy MYPROG1 from the source PDS to the target PDS and replace any existing version.
TSO COPYMBR MYPROG1 MYPROG2
Copy MYPROG1 from the source PDS to the target PDS and rename it to MYPROG2. Do not do the copy if MYPROG2 already exists on the target PDS.
TSO COPYMBR MYPROG1 MYPROG2 /r
Copy MYPROG1 from the source PDS to the target PDS and rename it to MYPROG2. Replace any existing version of MYPROG2 on the target PDS.
One of the things I like to do is to allocate my own REXX library to SYSPROC at TSO logon time so that I can execute REXX commands simply by typing in “TSO command_name” on the ISPF command line.
On the TSO logon screen I have a command setup to invoke a REXX exec that will do that for me:
BEFORE just says to allocate my REXX library before the existing allocations so that anything in my library overrides anything in the existing allocation with the same name (useful for testing changes to existing EXECs). Specify ‘AFTER’ or let it default to allocate your library AFTER the existing allocations.
This is the exec (called ALLOCREX in the above screen shot):
/* rexx */ /* logon exec to concat my rexx library to SYSPROC so that */ /* I can run my own rexx commands easily without having */ /* to specify the dataset name. EG TSO MYEXEC */ /* */ parse arg opt /* BEFORE or AFTER (default) */ lib=userid()||".REXX" /* dsn of rexx lib to alloc */ if x> 4 then do say "Unable to locate '"lib"'." say 'SYSPROC alloc not changed.' signal exit end rc=ddns('SYSPROC') /* get current SYSPROC allocation */ /* extract dsns and check for my rexx lib already alloc */ list='' comma='' do while queued() > 0 parse pull dsn if dsn=lib then do say lib 'already concat to SYSPROC.' say 'SYSPROC alloc not changed.' signal exit end list=list||comma||"'"||strip(dsn)||"'" comma=',' end oldlist=list /* add my rex lib to the list and realloc the DD */ if opt = 'BEFORE' then do list="'"lib"',"||list end else do list=list||",'"lib"'" end "ALLOC F(SYSPROC) DATASET("list") SHR REUSE" allocrc=rc if allocrc <> 0 then do say 'Alloc of SYSPROC faiuled with rc='allocrc say 'Restoring original allocation' "ALLOC F(SYSPROC) DATASET("oldlist") SHR REUSE" end /* queue an ISPF command so this exec can end */ exit: queue 'ISPF' return 0 /*---------------------------------------------------------*/ ddns: procedure /*---------------------------------------------------------*/ /* Find dsns allocated to a specified ddname */ /* Output returned on the stack */ /*---------------------------------------------------------*/ /* */ parse arg ddname upper ddname x=outtrap("out.","*","noconcat",1) address TSO 'listalc status' if out.0 = 0 then do return 0 /* Nothing found */ end foundDD="N" do i=1 to out.0 by 2 parse var out.i dsn . j=i+1 ddn=strip(substr(out.j,3,8)) if ddn <> "" & ddn = ddname then foundDD="Y" if ddn <> "" & ddn <> ddname then foundDD="N" if foundDD = "Y" then do push dsn end end return 0