Hi Folks,
I am trying to generate a SAS Data Set out of the DeploymentRegistry.txt (see: https://support.sas.com/kb/35/968.html ). Basicyally, this is a text file which lists for each product component of your SAS installation several information bits (like version, display name, applied hot fixes, etc.).
So far I have this code
data test;
length Host $5. ;
length Product $15.;
length Version $10.;
length Display_Name $100.;
length Display_Version $10.;
infile _tst truncover;
input;
len= length(_infile_);
if _infile_ =: " Host" then
Host = scan(_infile_,2,":") ;
if _infile_ =: " Product" then
Product = scan(_infile_,2,":");
if _infile_ =: " Version" then
Version = scan(_infile_,2,":");
if _infile_ =: " Display Name" then
Display_Name = scan(_infile_,2,":");
if _infile_ =: "Display Version" then
Display_Version = scan(_infile_,2,":");
if length(_infile_) < 2 then delete;
run;
But this produces multiple lines for each product component which I want in one line.
So instead of this:
I want this:
Any hints as In which way I'd have to modify my code?
Maybe use the retain statement???
Cheers,
FK1
This code does something similar although it outputs to the SAS log
options nomprint nomprintnest nomlogic nomlogicnest nosymbolgen nosource nosource2;
/* Parse Registry File */
/* v0.1 */
/* Andy.Mayes@SAS.COM */
/* Feb 2021 */
/* Updates */
/* 17FEB2021 deculp Traverse directory and parse each registry file in the directory */
/* 18Feb2021 snzroo Merged my changes to Dereks and formatted output example:
*******************************************************************************
Filename 1: Meta-DeploymentRegistry.txt
*******************************************************************************
===============
HOT FIX SUMMARY
Meta-DeploymentRegistry.txt
===============
SAS Thread-safe Compiler and Symbolic Differentiator 9.57
SAS Model Implementation Platform Server Configuration 3.2
SAS High-Performance Risk Server Component 4.2 F7P004
===============
*******************************************************************************
Filename 2: Mid-DeploymentRegistry.txt
*******************************************************************************
===============
HOT FIX SUMMARY
Mid-DeploymentRegistry.txt
===============
SAS Infrastructure for Risk Management Mid-Tier 3.6
SAS Thread-safe Compiler and Symbolic Differentiator 9.57
SAS Risk and Finance Workbench Mid-Tier 3.2 D4N006
=============== */
/* 22Feb2021 snzroo Small changes to improve output, and restrict to files with a specific externsion */
/* 04Mar2021 snzroo RegistryParser_rev04.sas
Added file match set fileMatch macro variable to PERL Regular Expression
Only processes files that match the expression
This allows code to run against directory with multiple files and only
report on required registry reports e.g.
FileMatch=DeploymentRegistry\.txt
Will only analyse files that have DeploymentRegistry.txt in their file name
EXT macro no longer required
*/
/* 20Apr2021 snzroo RegistryParser_rev05.sas
Fixed warning message
*/
/* 19Jul2022 snzroo RegistryParser_rev06.sas
Removed the need to define the ext macro variable
Now code pulls the file extenstion (ext) from the fileMatch
*/
/* Instructions */
/* 1. Set VRDIR to the directory that contains the ViewRegistry Reports */
/* 2. Set EXPR to the SAS components to find and report using a PERL Regular Expression */
/* 3. DELETE - Set EXT to the file extension you want to interrogate */
/* 3. Set fileMatch to a regular expression to find matching files */
/* 4. Submit program, and view results in the SAS log */
%let vrdir = <Change this> ;
/* SNZROO 2022-07-19 Start */
/* Remove the need to define the ext macro */
/* %let ext = txt; /**/
/* SNZROO 2022-07-19 End */
/*
fileMatch = DeploymentRegistry.*\.txt
Searches for any file "DeploymentRegistry<other characters>.txt"
*/
%let fileMatch = .*DeploymentRegistry.*\.txt* ;
/* %let expr = modimp|modimpsvr|modimpmiddoc|modimpmid|modimpsvrc|modimpsvr; /**/
%let rfw = stresssvr|stressmid|ssrsvr|ssrsvrc|stressmid; /* RFW */
%let irm = rmifirmmvac|riskminmid|rmifirmmva; /* IRM 3.6 */
%let cmp = cmp|tkcmp ; /* SAS (Thread-safe) Compiler and Symbolic Differentiator */
%let hpr = hprisksvr|riskcmnmid|hpriskmid|risk|rskwkgpmid ; /* HPRISK */
%let mip = modimpmid|modimpsvr|riskmodedmid ; /* MIP */
%let rgf = rskmgtsvr|rgpmid|rgpadm ;
%let expr = base|hprisksvr|risk|hpriskmid|modimp|cmp|tkcmp|stressmid|stresssvrc|stresssvr|modimpsvr|modimpmiddoc|modimpmid|modimpsvrc|modimpsvr; /**/
%let expr = &hpr|&mip ;
* options mlogic mprint symbolgen ;
%macro list_hot_fixes(dir,fname,expr);
filename regfile "&dir.\&fname.";
data readReg;
file="&fname" ;
reProduct = prxparse("/Product: (&expr.)/");
reDisplayName = prxparse("/Display Name:/") ;
deDisplayName = prxparse("s/Display Name://") ;
reVersion = prxparse("/Version:/") ;
deVersion = prxparse("s/(Version:)|(Display Version:)//") ;
*deVersion = prxparse("s/Version://") ;
reHotFixEntry = prxparse("/Hot Fix Entry: Hotfix/") ;
deHotFixEntry = prxparse("s/Hot Fix Entry: Hotfix//") ;
infile regfile;
input;
/* Scan for Product */
*if findw(_infile_,"risk") then do ;
if prxmatch(reProduct,_infile_) then do;
* put "PRODUCT : " _infile_;
/* Repeat until end of Product */
hotFixFound=0;
do until(findw(_infile_,"-----"));
input;
* put _infile_;
if prxmatch(reDisplayName,_infile_) then do ;
displayname=prxchange(deDisplayName,1,_infile_) ;
* put "Display Name: " _infile_ ;
end ;
else if prxmatch(reVersion,_infile_) then do ;
version=prxchange(deVersion,1,_infile_) ;
* put "VERSION : " _infile_ ;
end ;
else if prxmatch(reHotFixEntry,_infile_) then do ;
* put "HOT FIX : " _infile_ ;
hotFixFound=1 ;
hotFix=prxchange(deHotFixEntry,1,_infile_) ;
output ;
end ;
end ;
if hotFixFound=0 then
output ;
end ;
run ;
/* Pull version */
/* Pull Hot Fixes */
proc sort data=readreg out=srtdReg ;
by displayname ;
run ;
data _null_ ;
set srtdReg;
by displayname ;
if last.displayname then
put displayname @75 version @85 hotfix ;
run ;
%mend list_hot_fixes;
%macro get_viewregistry_files(fr,dir,type);
%global nfiles;
proc sql noprint;
/* Get number of files */
select count(fname) into : nfiles
from work.vrfiles
;
%let nfiles=%trim(%left(&nfiles));
/* Assign each filename to a macro variable */
%do zz=1 %to &nfiles;
%global fname&zz;
%global ext&zz;
%end;
select fname into : fname1 - : fname%trim(&nfiles)
from work.vrfiles
;
select ext into : ext1 - : ext%trim(&nfiles)
from work.vrfiles
;
quit;
%do i=1 %to &nfiles ;
%put DEBUG - &&fname&i ;
%end ;
%mend get_viewregistry_files;
%macro list_hfs_by_vrfile(fileref,type);
/* For each ViewRegistry Report, list the release details for the relevant components */
%get_viewregistry_files(&fileref,&vrdir,&type);
options nosymbolgen nonotes nomprint nomprintnest nomlogic nomlogicnest nosource nosource2;
/* dm 'clear log'; SNZROO 04/07/21 commenting this out, as I want to see the full log */
%put ;
%put ;
%put List of files in: &vrdir;
%put ;
%put With ViewRegistry details where:;
%put File extension is: &type;
%put And hot fix component is in: &expr;
%put ;
%put ;
%do ii = 1 %to &nfiles;
%put ;
%put ;
%put *******************************************************************************;
%put Filename &&ii: &&fnameⅈ
%put *******************************************************************************;
%put ;
/* %if %UPCASE(&&ext&ii)=%UPCASE(&type) %then %do; */
%list_hot_fixes(&vrdir,&&fname&ii,&expr);
/* %end; */
%end;
%mend list_hfs_by_vrfile;
/* Store each filename in the ViewRegistry directory in a SAS data set */
filename v "&vrdir";
data work.vrfiles (keep=fname ext);
reFileMatch = prxparse("/&FileMatch./");
did=dopen("v");
filecount=dnum(did);
do i=1 to filecount;
fname=dread(did,i);
put fname= ;
ext=trim(scan(fname,-1,".","r"));
lext=length(ext);
lfil=length(fname);
/* SNZROO 2022-07-19 Start */
/* Remove the need to define the ext macro */
call symput("ext",ext) ;
/* SNZROO 2022-07-19 End */
/*file=substr(fname,1,lfil-lext-1);*/
/*if ext="&ext" then */
if prxmatch(reFileMatch,fname) then
output;
end;
rc=dclose(did);
run;
%list_hfs_by_vrfile(v,&ext);
RETAIN the values of variables. That will keep values across iterations of the data step boundary.
Then when you get to the last item use an explicit OUTPUT call to write to the data set then reset the retained values to missing after writing to the set . When you have an explicit OUTPUT (or multiple) that is the only time the data gets written to the output set.
Call Missing is the easiest way to set a bunch of variables to missing as that is what is designed to do.
data test; length Host $5. ; length Product $15.; length Version $10.; length Display_Name $100.; length Display_Version $10.; Retain Host product version display_name display_version; infile _tst truncover; input; len= length(_infile_); if _infile_ =: " Host" then Host = scan(_infile_,2,":") ; if _infile_ =: " Product" then Product = scan(_infile_,2,":"); if _infile_ =: " Version" then Version = scan(_infile_,2,":"); if _infile_ =: " Display Name" then Display_Name = scan(_infile_,2,":"); if _infile_ =: "Display Version" then Display_Version = scan(_infile_,2,":"); if not missing(display_version) then output;
call missing(Host, product, version, display_name, display_version); if length(_infile_) < 2 then delete; run;
Hey everyone,
thank's a lot for all your helpful advice.
I finally came up with this, which works in 99% of the cases, where there are not hot fixes:
%LET SLSH = %qsysfunc(ifc(%UPCASE(&SYSSCP) = WIN,\,/));
%*PUT &=SLSH;
** get location of SAS installation: **;
%LET SASROOT = %SYSGET(SASROOT);
%*PUT &=SASROOT;
** get SASHOME level for applications and such **;
%LET SASHOME = %SYSGET(SASHOME);
%*PUT &=SASHOME;
** Temporary Folder for registry report files **;
%LET _regrepfolder = %SYSFUNC(pathname(WORK))&SLSH.REPSTUFF;
%PUT &=_regrepfolder;
/*Allocate temporary file for Output of Registry Report in subfolder of WORK-path*/
option DLCREATEDIR;
LIBNAME _regrep "&_regrepfolder.";
/*Generate fresh registry report (see: https://support.sas.com/kb/35/968.html)*/
data _NULL_;
call system("&SASHOME&SLSH.SASPrivateJavaRuntimeEnvironment&SLSH.9.4&SLSH.jre&SLSH.bin&SLSH.java -jar &SASHOME&SLSH.deploymntreg&SLSH.sas.tools.viewregistry.jar -out &_regrepfolder." );
run;
filename regfile "&_regrepfolder.&SLSH.DeploymentRegistry.txt";
data readReg (drop=_numeric_);
reHost = prxparse("/Host:/");
deHost = prxparse("s/Host://");
reProduct = prxparse("/Product:/");
deProduct = prxparse("s/Product://");
reVersion = prxparse("/Version:/") ;
deVersion = prxparse("s/Version://") ;
/*
reVersion = prxparse("/Version:/") ;
deVersion = prxparse("s/(Version:)|(Display Version:)//") ;
*/
reDisplayName = prxparse("/Display Name:/") ;
deDisplayName = prxparse("s/Display Name://") ;
reHotFixEntry = prxparse("/Hot Fix Entry: Hotfix/") ;
deHotFixEntry = prxparse("s/Hot Fix Entry: Hotfix//") ;
reDisplayVersion = prxparse("/Display Version:/") ;
deDisplayVersion = prxparse("s/Display Version://") ;
infile regfile;
input;
/* Scan for Product */
if prxmatch(reHost,_infile_) then do;
host=prxchange(deHost,1,_infile_) ;
* put "PRODUCT : " _infile_;
/* Repeat until end of Product */
hotFixFound=0;
do until(findw(_infile_,"-----"));
input;
* put _infile_;
if prxmatch(reDisplayName,_infile_) then do ;
displayname=strip(prxchange(deDisplayName,1,_infile_)) ;
* put "Display Name: " _infile_ ;
end ;
else if prxmatch(reDisplayVersion,_infile_) then do ;
displayversion=strip(prxchange(deDisplayVersion,1,_infile_)) ;
* put "Display Version: " _infile_ ;
end ;
else if prxmatch(reProduct,_infile_) then do ;
product=strip(prxchange(deProduct,1,_infile_)) ;
end;
else if prxmatch(reVersion,_infile_) then do ;
version=strip(prxchange(deVersion,1,_infile_)) ;
* put "VERSION : " _infile_ ;
end ;
else if prxmatch(reHotFixEntry,_infile_) then do ;
* put "HOT FIX : " _infile_ ;
hotFixFound=1 ;
hotFix=strip(prxchange(deHotFixEntry,1,_infile_)) ;
output ;
end ;
end ;
if hotFixFound=0 then output ;
end ;
run ;
Only problem left: in case a product has a hot fix, then the respective line does not have a value for "displayname" even though in the registry file there is one:
Has anybody an idea how to fix this issue?
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.