Note: This blog was originally published in November 2017. It has been updated to include links to IBM’s software announced September 2019.
A little while back, I talked about mvscmd, which lets me run MVS programs from the z/OS USS environment (the UNIX shell).
I’ve written a few utilities that are now part of IBM Z Open Automation Utilities, which is provided as a free FMID in a few different IBM products including IBM Dependency Based Build, IBM Z Open Development, and IBM Developer for z/OS Enterprise Edition.
dls (dataset list)
dls takes a prefix as input and lists the datasets that start with that prefix. As an example, I have a bunch of test datasets that start with IBMUSER.MVSCMD. I can list them all to the console as follows:
dls ibmuser.mvscmd
(the prefix is case-insensitive because datasets are upper-case only). Here is the output:
IBMUSER.MVSCMD.ADRDSU.DAR IBMUSER.MVSCMD.BIND.OBJ ... IBMUSER.MVSCMD.TSO.REXX
Here is a simplified version of dls:
if [ -z "$1" ]; then echo 'Syntax: dls <dataset-prefix>' echo 'Example: dls IBMUSER.MVSCMD' exit 16 else datasetprefix=$1; datasetprefix=$(echo ${datasetprefix} | tr '[:lower:]' '[:upper:]') fi ( echo " LISTCAT -\n LEVEL(${datasetprefix}\n" | mvscmdauth --pgm=idcams --sysprint=* --sysin=stdin | awk '/0NONVSAM/ { print $3 }' )
mls (PDS member list)
mls takes as input a PDS (or PDSE) and lists the members. I can list the members of the fully-qualified PDS IBMUSER.MVSCMD.C as follows:
mls ibmuser.mvscmd.c
Again, the dataset name is case-insensitive. Here’s the output:
ERR MAIN
Here is a simplified version of mls:
if [ -z "$1" ]; then echo 'Syntax: mls <dataset>' echo 'Example: mls SYS1.PARMLIB' exit 16 else dataset=$1; fi tsocmd listds "'"${dataset}"'" members 2>/dev/null | tail +7
dgrep (Dataset simplistic ‘grep’)
dgrep takes as input a string and a pattern of datasets to search across. I can search for the string rexx across all datasets with the pattern IBMUSER.MVSCMD.TSO.* as follows:
dgrep rexx ibmuser.mvscmd.tso.*
Here’s the output:
LINE-# SOURCE SECTION SRCH DSN: IBMUSER.MVSCMD.TSO.REXX OPERCMD --------- STRING(S) FOUND ------------------- 1 /* REXX */
Here is a simplified version of dgrep:
if [ -z "$2" ]; then echo 'dgrep <str> <dataset-pattern>' echo ' example: dgrep rexx IBMUSER.MVSCMD.TSO.*' exit 16 else str=$1; datasetpattern=$2; datasetpattern=$(echo ${datasetpattern} | tr '[:lower:]' '[:upper:]') fi datasets=`echo " LISTCAT -\n ENTRIES("${datasetpattern}")\n" | mvscmdauth --pgm=idcams --sysprint=* --sysin=stdin | awk '/0NONVSAM/ { print $3 }' ` for dataset in ${datasets}; do echo "SRCHFOR '"${str}"'\n" | mvscmd --pgm=isrsupc --args='SRCHCMP,ANYC,IDPRFX,NOSUMS,LONGLN,NOPRTCC' --newdd=${dataset} --outdd=* --sysin=stdin | awk '!/ ISRSUPC/'; done
dzip: dataset zip
I have one more example, which took me awhile to get working, but could be really handy. It’s not part of the utilities, but I include it here as another example of the mvscmdauth utility. dzip takes a set of datasets as input and dumps them into a ‘blob’ using ADRDSSU. It then packs that ‘blob’ into an FB 1024 file that can be sent to other systems (or off-platform for backup).
I can backup all my datasets that start with IBMUSER.MVSCMD as follows:
dzip IBMUSER.MVSCMD.**
Here’s the (pruned) output:
- DUMP OUTDD(ARCHIVE) - DS(INCL(IBMUSER.MVSCMD.**) ADR101I (R/I)-RI01 (01), TASKID 001 HAS BEEN ASSIGNED TO COMMAND 'DUMP ' ADR016I (001)-PRIME(01), RACF LOGGING OPTION IN EFFECT FOR THIS TASK 0ADR412E (001)-DTDSC(03), DATA SET IBMUSER.MVSCMD.LOAD IN CATALOG CATALOG.Z22C.MASTER ON VOLUME C2SYS1 FAILED SERIALIZATION AND 0 FAILED FOR OTHER REASONS 0ADR454I (001)-DTDSC(01), THE FOLLOWING DATA SETS WERE SUCCESSFULLY PROCESSED 0 IBMUSER.MVSCMD.ADRDSU.DAR ... 0 IBMUSER.MVSCMD.TSO.REXX TASK 001 ** AMA572I STARTING TERSE ENCODE SPACK 18:10:19 11/02/2017 **** ** AMA527I INPUT - DDNAME : SYSUT1 DSNAME: IBMUSER.DZIP.TEMP.D31917 ** AMA528I OUTPUT - DDNAME : SYSUT2 DSNAME: IBMUSER.DZIP.TEMP.D31917.TRS ** AMA583I INPUT DATASET SIZE IN BYTES: 1110619 OUTPUT DATASET SIZE IN BYTES: 72704 COMPRESSION RATIO: 6% ** AMA573I TERSE COMPLETE ENCODE SPACK 18:10:20 11/02/2017 **** ** AMA504I RETURN CODE: 0 Datasets of pattern: IBMUSER.MVSCMD.** zipped to: /tmp/d31917.dzp
My dataset zip file is written to /tmp/d31917.dzp (this cries out for options to control the output file name). Note that one of the files IBMUSER.MVSCMD.LOAD was not dumped because it is in use. I could use binary transfer to move this zip anywhere. I can unzip the dataset zip file on a different z/OS system using dunzip, with a different high-level qualifier IBMTEST, as follows:
dunzip /tmp/d31917.dzp IBMTEST
Here’s the (copious) output that I have pruned:
... ** AMA583I INPUT DATASET SIZE IN BYTES: 72704 OUTPUT DATASET SIZE IN BYTES: 1110619 COMPRESSION RATIO: 6% ... 0ADR395I (001)-NEWDS(01), DATA SET IBMUSER.MVSCMD.ADRDSU.DAR ALLOCATED WITH NEWNAME IBMTEST.MVSCMD.ADRDSU.DAR, ON VOLUME(S): C2DBAR ... 0ADR454I (001)-TDLOG(01), THE FOLLOWING DATA SETS WERE SUCCESSFULLY PROCESSED 0 IBMUSER.MVSCMD.ADRDSU.DAR ... 0ADR013I (001)-CLTSK(01), 2017.306 18:19:05 TASK COMPLETED WITH RETURN CODE 0000 0ADR012I (SCH)-DSSU (01), 2017.306 18:19:05 DFSMSDSS PROCESSING COMPLETE. HIGHEST RETURN CODE IS 0000
Please note: ADRSSU first extracts each dataset to the original source name, then renames the dataset to the target name. Therefore the ID that does the unzip has to have SAF authority for both the original dataset name and the target dataset name. In my example, I need to be able to create datasets starting with IBMUSER -and- IBMTEST. If someone knows how to eliminate this restriction through using ADRDSSU a different way, tell me.
dzip:
# # simple program that 'zips' (archives) a set of datasets into a blob # if [ -z "$1" ]; then echo 'dzip <dataset-pattern>' echo ' example: dzip IBMUSER.MVSCMD.**' exit 16 else datasetpattern=$1; fi hlq=`./hlq` rnd=${RANDOM} tempds="${hlq}.DZIP.TEMP.D${rnd}" temphfs=/tmp/d${rnd}.dzp tso "alloc dsn('${tempds}') recfm(u) lrecl(0) dsorg(ps) dsntype(basic) catalog tracks space(1000,1000)" >/dev/null 2>&1 tso "alloc dsn('${tempds}.TRS') recfm(f,b) lrecl(1024) dsorg(ps) dsntype(basic) catalog tracks space(1000,1000)" >/dev/null 2>&1 ( echo " DUMP OUTDD(ARCHIVE) -\n DS(INCL(${datasetpattern}))" | mvscmdauth --pgm=ADRDSSU --archive=${tempds},old --sysin=stdin --sysprint=stdout | awk '!/1PAGE|ADR109I|ADR006I|ADR801I|ADR006I|ADR013I|ADR012I/' ) mvscmd --pgm=AMATERSE --args='SPACK' --sysut1=${tempds} --sysut2=${tempds}.TRS --sysprint=* cp -B "//'"${tempds}.TRS"'" ${temphfs} echo "Datasets of pattern: ${datasetpattern} zipped to: ${temphfs}" tsocmd "delete '${tempds}'" >/dev/null 2>&1 tsocmd "delete '${tempds}.TRS'" >/dev/null 2>&1
dunzip:
# # simple program that 'unzips' (restores) a blob into a set of datasets with an optional new HLQ # #set -x if [ -z "$1" ]; then echo 'dunzip <src> [<HLQ>]' echo ' Unzip datasets from <src> archive, changing HLQ of datasets to <HLQ>' echo ' example: dunzip /tmp/d38382.dzp TEST' exit 16 else infile=$1; if [ -z "$2" ]; then newhlq=`./hlq` else newhlq=$2 fi fi hlq=`./hlq` rnd=${RANDOM} tempds="${hlq}.DZIP.TEMP.D${rnd}" tso "alloc dsn('${tempds}') recfm(u) lrecl(0) dsorg(ps) blksize(27998) dsntype(basic) catalog tracks space(1000,1000)" >/dev/null 2>/dev/null tso "alloc dsn('${tempds}.TRS') recfm(f,b) lrecl(1024) dsorg(ps) dsntype(basic) catalog tracks space(1000,1000)" >/dev/null 2>/dev/null cp -Wseqparms='recfm=*' -B ${infile} "//'"${tempds}.TRS"'" mvscmd --pgm=AMATERSE --args='UNPACK' --sysut1=${tempds}.TRS --sysut2=${tempds} --sysprint=* echo " RESTORE INDD(ARCHIVE) -\n DS(INCL(**)) -\n CATALOG -\n RENUNC(${newhlq})" | mvscmdauth --pgm=ADRDSSU --archive=${tempds} --sysin=stdin --sysprint=stdout tsocmd delete "'"${tempds}"'" >/dev/null 2>&1 tsocmd delete "'"${tempds}.TRS"'" >/dev/null 2>&1
A few of my scripts reference a tool called hlq.
Simplified version of hlq:
# # print the hlq for this TSO user to the screen # tso profile 2>/dev/null | awk '/IKJ56688I/ { print $11; }' | /bin/sed -e "s/PREFIX(\([A-Z]*\))/\1/"
Leave a comment