-
Notifications
You must be signed in to change notification settings - Fork 0
/
dirbetter.m
80 lines (73 loc) · 2.63 KB
/
dirbetter.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
% replacement for dir with behaviour that more closely resembles unix ls or
% python glob.
%
% Changes relative to dir:
% 1) file.abspath preserves input pattern path
% 2) '.' and '..' outputs are suppressed. Note that this has consequences
% if you were using something like isempty(dir(x)) to test for valid
% paths. You should probably use isdir or exist for this instead.
% 3) multi-level wildcards are supported. Behaviour here is more like unix
% ls than find - we don't recurse into sub-directories beyond what the
% search pattern specifies.
%
% EXAMPLES:
% dirbetter('~/temp/*/*/*.png') % return PNGs 2 directories down from
% ~/temp.
% dirbetter('~/temp/*') % return any file/directory inside ~/temp itself
%
% 2016-12-06 J Carlin
%
% file = dirbetter(pattern)
function file = dirbetter(pattern)
wildcard = find(pattern=='*');
dirsep = find(pattern==filesep);
% matlab's dir has a very straightforward limitation: filesep AFTER
% wildcard is not supported
badwild = find(wildcard < max(dirsep),1,'first');
if isempty(badwild)
% so in this scenario all is well
file = absdir(pattern);
return
end
% we need to unpack the wildcards
% first work out how far we can go before we hit a problem
targetsep = dirsep(dirsep > wildcard(badwild));
[~,ind] = min(targetsep-wildcard(badwild));
finalind = targetsep(ind);
partialpattern = pattern(1:finalind-1);
remainingpattern = pattern(finalind+1:end);
partialhit = absdir(partialpattern);
wasdir = find(arrayfun(@(x)x.isdir,partialhit,'uniformoutput',1));
file = struct('name',{},'date',{},'bytes',{},'isdir',{},...
'datenum',{},'abspath',{});
for w = 1:numel(wasdir)
% construct a new search pattern (which resolves out the first
% wildcard)
newpattern = fullfile(partialhit(wasdir(w)).abspath,remainingpattern);
% fullfile sometimes adds a filesep to the end of the path
if newpattern(end)==filesep
newpattern(end) = [];
end
% and recurse to collect all the hits (so we will recurse to the same
% number of levels as the nuber of wildcards)
newhit = dirbetter(newpattern);
if ~isempty(newhit)
% this extra conditional is needed to avoid growing a [0,n] struct
% array.
file = [file; newhit];
end
end
function hits = absdir(pattern)
hits = dir(pattern);
% need this so that empty structs (no hits) also have this field
[hits.abspath] = deal([]);
% always eliminate parent dir and current dir
hits(strcmp({hits.name},'..')) = [];
hits(strcmp({hits.name},'.')) = [];
root = pattern;
if ~isdir(root)
root = fileparts(pattern);
end
for thishit = 1:numel(hits)
hits(thishit).abspath = fullfile(root,hits(thishit).name);
end