I would like to delete the folder folderToDelete, which contains subfolders and those folders might contain subfolders, and so on.
I do not have permission to do the x command.
I have the following code (after looking at the following post Delete folder (directory) and all files in it😞
%macro delete_folder(folderToDelete);
data work.FilesToDelete;
length Name $ 100;
keep Name;
rc = filename("folder", "&folderToDelete.");
dirId = dopen("folder");
do i = 1 to dnum(dirID);
Name = dread(dirId, i);
output;
end;
rc = dclose(dirId);
run;
data _null_;
set work.FilesToDelete end=lastDeleted;
put "Deleting " Name;
rc = filename("delfile", cats("&folderToDelete./", Name));
rc = fdelete("delfile");
put "del file " rc=;
rc = filename("delfile");
if lastDeleted then do;
put "Deleting the folder '&folderToDelete.'";
rc = filename("folder", "&folderToDelete.");
rc = fdelete("folder");
put "del folder " rc=;
rc = filename("folder");
end;
run;
%mend;
However, since my folder contains subfolders, only the tables are delete and not the subfolders, resulting in the main folder not being deleted. In that sense, what I would like was to apply a function recursively to delete every file inside any subfolder (or any other suggestion you might have).
As an example, if my folder has the following structure:
> folder
> subfolder_1
> T_1_1.sas7bdat
> T_1_2.sas7bdat
> T_1_3.sas7bdat
> subsubfolder_1
> T_1_1_1.sas7bdat
> subfolder_2
> T_2_1.sas7bdat
> T_1.sas7bdat
> T_2.sas7bdat
> T_3.sas7bdat
> T_4.sas7bdat
after running the first data step, which reads the folder, I get
Name |
subfolder_1 |
subfolder_2 |
T_1.sas7bdat |
T_2.sas7bdat |
T_3.sas7bdat |
T_4.sas7bdat |
and then in the second data step, only the tables are deleted.
However, I would like to delete the entirety of the folder. Can someone help?
You could use the %dirtree macro that I found here: https://github.com/sasutils/macros/blob/master/dirtree.sas
%macro dirtree
/*---------------------------------------------------------------------------
Build dataset of files in directory tree(s)
----------------------------------------------------------------------------*/
(directory /* Pipe delimited directory list (default=.) */
,out=dirtree /* Output dataset name */
,maxdepth=120 /* Maximum tree depth */
);
/*---------------------------------------------------------------------------
Use SAS functions to gather list of files and directories
directory - Pipe delimited list of top level directories
out - Dataset to create
maxdepth - Maximum depth of subdirectories to query
Output dataset structure
--NAME-- Len Format Description
FILENAME $256 Name of file in directory
TYPE $1 File or Directory? (F/D)
SIZE 8 COMMA20. Filesize in bytes
DATE 4 YYMMDD10. Date file last modified
TIME 4 TOD8. Time of day file last modified
DEPTH 3 Tree depth
PATH $256 Directory name
Size is not available for the directories.
LASTMOD timestamp is only available on Unix for directories.
Will not scan the subtree of a directory with a path that is
longer then 256 bytes. For such nodes TYPE will be set to L .
----------------------------------------------------------------------------*/
%local fileref ;
%let fileref=__FL__ ;
%if 0=%length(&directory) %then %let directory=. ;
* Setup dataset and seed with starting directory list ;
data &out;
length filename $256 type $1 size 8 date time 4 depth 3 path $256 ;
retain filename ' ' depth 0 type ' ' date . time . size . ;
format size comma20. date yymmdd10. time tod8. ;
do _n_=1 to countw(symget('directory'),'|');
path=scan(symget('directory'),_n_,'|');
output;
end;
run;
%* Allow use of empty OUT= dataset parameter ;
%let out=&syslast;
data &out;
modify &out;
retain sep "%sysfunc(ifc(&sysscp=WIN,\,/))";
retain maxdepth &maxdepth;
* Create FILEREF pointing to current file/directory ;
rc1=filename("&fileref",catx('/',path,filename));
if rc1 then do;
length message $256;
message=sysmsg();
put 'ERROR: Unable to create fileref for ' path= filename= ;
put 'ERROR- ' message ;
stop;
end;
* Try to open as a directory to determine type ;
did=dopen("&fileref");
type = ifc(did,'D','F');
if type='D' then do;
* Make sure directory name is not too long to store. ;
if length(catx('/',path,filename)) > vlength(path) then do;
put 'NOTE: Directory name too long. ' path= filename= ;
type='L';
rc3=dclose(did);
end;
else do;
* Move filename into the PATH and if on Unix set lastmod ;
path=catx(sep,path,filename);
filename=' ';
if sep='/' then do;
lastmod = input(dinfo(did,doptname(did,5)),nldatm100.);
date=datepart(lastmod);
time=timepart(lastmod);
end;
end;
end;
else do;
* For a file try to open file and get file information ;
fid=fopen("&fileref",'i',0,'b');
if fid then do;
lastmod = input(finfo(fid,foptname(fid, 5)), nldatm100.);
date=datepart(lastmod);
time=timepart(lastmod);
size = input(finfo(fid,foptname(fid,ifn(sep='/',6,4))),32.);
rc2 = fclose(fid);
end;
end;
* Update the observation in the dataset ;
replace;
if type='D' then do;
* When current file is a directory add directory members to dataset ;
depth=depth+1;
if depth > maxdepth then put 'NOTE: ' maxdepth= 'reached, not reading members of ' path= ;
else do i=1 to dnum(did);
filename=dread(did,i);
output;
end;
rc3=dclose(did);
end;
* Clear the fileref ;
rc4=filename("&fileref");
run;
%mend dirtree;
Then use the macro to create a directory listing and delete all listed files and folders.
%let topFolderToDelete=c:\temp\deldirtest;
/* create table work.dirtree with directory listing */
%dirtree(&topFolderToDelete);
proc sort data=work.dirtree;
by DESCENDING path DESCENDING type;
run;
/** delete files and folders **/
/* 1. folder separator \ or / (Win or Unix/Linux)? */
data _null_;
set work.dirtree;
if find(path,'\') then sep='\';
else sep='/';
if not missing(sep) then
do;
call symputx('sep',sep);
stop;
end;
run;
/* 2. delete files and folders */
data _null_;
set work.dirtree;
by DESCENDING path DESCENDING type;
fname='tempfile';
if type='F' then
rc=filename(fname, catx("&sep",path,filename));
else
rc=filename(fname, path);
if rc = 0 and fexist(fname) then
rc=fdelete(fname);
rc=filename(fname);
run;
You could use the %dirtree macro that I found here: https://github.com/sasutils/macros/blob/master/dirtree.sas
%macro dirtree
/*---------------------------------------------------------------------------
Build dataset of files in directory tree(s)
----------------------------------------------------------------------------*/
(directory /* Pipe delimited directory list (default=.) */
,out=dirtree /* Output dataset name */
,maxdepth=120 /* Maximum tree depth */
);
/*---------------------------------------------------------------------------
Use SAS functions to gather list of files and directories
directory - Pipe delimited list of top level directories
out - Dataset to create
maxdepth - Maximum depth of subdirectories to query
Output dataset structure
--NAME-- Len Format Description
FILENAME $256 Name of file in directory
TYPE $1 File or Directory? (F/D)
SIZE 8 COMMA20. Filesize in bytes
DATE 4 YYMMDD10. Date file last modified
TIME 4 TOD8. Time of day file last modified
DEPTH 3 Tree depth
PATH $256 Directory name
Size is not available for the directories.
LASTMOD timestamp is only available on Unix for directories.
Will not scan the subtree of a directory with a path that is
longer then 256 bytes. For such nodes TYPE will be set to L .
----------------------------------------------------------------------------*/
%local fileref ;
%let fileref=__FL__ ;
%if 0=%length(&directory) %then %let directory=. ;
* Setup dataset and seed with starting directory list ;
data &out;
length filename $256 type $1 size 8 date time 4 depth 3 path $256 ;
retain filename ' ' depth 0 type ' ' date . time . size . ;
format size comma20. date yymmdd10. time tod8. ;
do _n_=1 to countw(symget('directory'),'|');
path=scan(symget('directory'),_n_,'|');
output;
end;
run;
%* Allow use of empty OUT= dataset parameter ;
%let out=&syslast;
data &out;
modify &out;
retain sep "%sysfunc(ifc(&sysscp=WIN,\,/))";
retain maxdepth &maxdepth;
* Create FILEREF pointing to current file/directory ;
rc1=filename("&fileref",catx('/',path,filename));
if rc1 then do;
length message $256;
message=sysmsg();
put 'ERROR: Unable to create fileref for ' path= filename= ;
put 'ERROR- ' message ;
stop;
end;
* Try to open as a directory to determine type ;
did=dopen("&fileref");
type = ifc(did,'D','F');
if type='D' then do;
* Make sure directory name is not too long to store. ;
if length(catx('/',path,filename)) > vlength(path) then do;
put 'NOTE: Directory name too long. ' path= filename= ;
type='L';
rc3=dclose(did);
end;
else do;
* Move filename into the PATH and if on Unix set lastmod ;
path=catx(sep,path,filename);
filename=' ';
if sep='/' then do;
lastmod = input(dinfo(did,doptname(did,5)),nldatm100.);
date=datepart(lastmod);
time=timepart(lastmod);
end;
end;
end;
else do;
* For a file try to open file and get file information ;
fid=fopen("&fileref",'i',0,'b');
if fid then do;
lastmod = input(finfo(fid,foptname(fid, 5)), nldatm100.);
date=datepart(lastmod);
time=timepart(lastmod);
size = input(finfo(fid,foptname(fid,ifn(sep='/',6,4))),32.);
rc2 = fclose(fid);
end;
end;
* Update the observation in the dataset ;
replace;
if type='D' then do;
* When current file is a directory add directory members to dataset ;
depth=depth+1;
if depth > maxdepth then put 'NOTE: ' maxdepth= 'reached, not reading members of ' path= ;
else do i=1 to dnum(did);
filename=dread(did,i);
output;
end;
rc3=dclose(did);
end;
* Clear the fileref ;
rc4=filename("&fileref");
run;
%mend dirtree;
Then use the macro to create a directory listing and delete all listed files and folders.
%let topFolderToDelete=c:\temp\deldirtest;
/* create table work.dirtree with directory listing */
%dirtree(&topFolderToDelete);
proc sort data=work.dirtree;
by DESCENDING path DESCENDING type;
run;
/** delete files and folders **/
/* 1. folder separator \ or / (Win or Unix/Linux)? */
data _null_;
set work.dirtree;
if find(path,'\') then sep='\';
else sep='/';
if not missing(sep) then
do;
call symputx('sep',sep);
stop;
end;
run;
/* 2. delete files and folders */
data _null_;
set work.dirtree;
by DESCENDING path DESCENDING type;
fname='tempfile';
if type='F' then
rc=filename(fname, catx("&sep",path,filename));
else
rc=filename(fname, path);
if rc = 0 and fexist(fname) then
rc=fdelete(fname);
rc=filename(fname);
run;
Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!
Check out this tutorial series to learn how to build your own steps in SAS Studio.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.