How to recursively add subdirectories to the PATH?

The following Does The Right Thing, including trimming hidden directories and their children and properly handling names with newlines or other whitespace:

export PATH="${PATH}$(find ~/code -name '.*' -prune -o -type d -printf ':%p')"

I use a similar trick for automatically setting CLASSPATHs.


If you really need to go down this road, you could try minimizing that PATHs list some more: drop folders that contain no executables. Of course, at the cost of even more stats. ;-/

PATH=$PATH$(find ~/code -name '.*' -prune -o -type f -a -perm /u+x -printf ':%h\n' | sort | uniq | tr -d '\n')

I'd avoid doing this at each shell spawn. Some kind of caching should be used. For instance, add this line to your ~/.bashrc:

[ -s ~/.codepath ] && export PATH=$PATH$(<~/.codepath)

and run

find ~/code -name '.*' -prune -o -type f -a -perm /u+x -printf ':%h\n' |sort |uniq |tr -d '\n' > ~/.codepath

only when you know something really changed.

EDIT: here's a rewrite without your missing -printf

find ~/code -name '.*' -prune -o -type f -a -perm /u+x -print | sed 's@/[^/]\+$@:@' | sort | uniq | tr -d '\n' | sed 's/^/:/; s/:$//'

Something like

my_path=$(find $root -type d | tr '\n' ':')

or

my_path=$(find $root -type d -printf '%p:')

At the end of your script, put the line:

PATH=${PATH}:$(find ~/code -type d | tr '\n' ':' | sed 's/:$//')

This will append every directory in your ~/code tree to the current path. I don't like the idea myself, preferring to have only a couple of directories holding my own executables and explicitly listing them, but to each their own.

If you want to exclude all directories which are hidden, you basically need to strip out every line that has the sequence "/." (to ensure that you don't check subdirectories under hidden directories as well):

PATH=${PATH}:$(find ~/code -type d | sed '/\/\\./d' | tr '\n' ':' | sed 's/:$//')

This will stop you from getting directories such as ~/code/level1/.hidden/level3/ (i.e., it stops searching within sub-trees as soon as it detects they're hidden). If you only want to keep the hidden directories out, but still allow non-hidden directories under them, use:

PATH=${PATH}:$(find ~/code -type d -name '[^\.]*' | tr '\n' ':' | sed 's/:$//')

This would allow ~/code/level1/.hidden2/level3/ but disallow ~/code/level1/.hidden2/.hidden3/ since -name only checks the base name of the file, not the full path name.

Tags:

File

Bash

Path