Finding out what directories exist with only basic shell builtins (a Unix shell trick)

Back in the old days of multi-architecture Unix environments , generally no two Unix vendors could agree on what should be in your $PATH . The core of /bin and /usr/bin was the same, but everyone had their own additional directories ( Solaris had a lot of them ). In addition, different local computing groups had different views on where local programs should go; /usr/local/bin, /local/bin, /opt/<something>/bin, /<group>/bin, and so on. This was a problem for me because I maintained a common set of dotfiles across all of the Unix systems I had accounts on , and I didn't want my $PATH to be a giant list of every possible directory on every system. So I needed to trim down a giant master list of possible $PATH directories to only the ones that existed on the current system, and to make it harder I wanted to use only shell builtins, in a shell where test wasn't a builtin.

Fortunately, there is one thing that has to be a builtin and has to fail if a directory doesn't exist (or isn't usable by you), namely cd . Using cd as a substitute for ' test -d ' is a bit odd, but it works. My shell has real lists, so I could write this as more or less:

# potential $PATH entries in $candidates
path=`{ tpath=()
        for (pe in $candidates)
           builtin cd $pe >[1=] >[2=] && tpath=($tpath $pe)
        echo $tpath }

(This doesn't work for relative paths, but I didn't have any in my $PATH .)

Because all shells have to have cd as a builtin, this same trick could be used in pretty much any shell. Bourne style shells make you work a bit harder to put together $PATH ; at a minimum you need to stick :'s between every element ( cf ), and maybe your equivalent of $candidates also uses :'s to separate entries and so you have to split it up on those.

(In a Bourne shell I would make $candidates just be quoted and space separated, because that's a lot simpler to deal with. This wouldn't handle a $PATH entry that had spaces in it, but you don't normally see those.)

Using cd this way is a trick, but tricks are what you're forced into in a minimal shell environment where you don't want to run external programs. In actual practice, I wound up writing a little C program to do this and relying on that on systems that I used frequently enough to compile it for them. The implementation with cd was only a fallback for systems and situations without my isdirs program.

(This is sort of a followup to a Unix shell trick , which was also about something that I had to do for cross-architecture dotfiles.)

PS: All of this comes from the days when systems were slow enough that you tried to avoid running additional external programs in your shell dotfiles, which is why I wanted to do it all with shell builtins instead of running a lot of test s or the like. And most modern shells have test as a builtin anyway.