I've used a few solutions for this:
1. Use find
to dynamically generate $PATH
For this, I've used a couple similar but slightly modified approaches. Suppose you have the following structure:
~/apps
├── foo
│ └── bin
├── bar
│ └── bin
└── blah
We can...
a. add existing apps/*/bin/ folders to $PATH
This will search for any bin/ directories in $HOME
/apps/* and add them to the $PATH
when your shell loads, skipping any directories which don't have a bin/ sub-directory.
#.bashrc
bins=$(
find "$HOME/apps/" -maxdepth 2 -type d -name 'bin' \
| tr '\n' ':' \
| sed 's/:$//'
)
export PATH="$bins:$PATH"
Produces:
/home/user/apps/foo/bin:/home/user/apps/bar/bin:...
b. add any somedir/*/bin/ to $PATH
...regardless of whether or not each folder in somedir/ actually has a bin/ sub-directory in it. That means, for the above directory structure, even apps/blah/bin will be added to the $PATH
-- even though it doesn't exist!
This is useful when one of your directories doesn't currently have a bin/ sub-directory, but it very well could in the future, and you don't want to have to reload your shell for it to be added to your $PATH
after you create it.
#.bashrc
bins=$(
find "$HOME/apps/" -maxdepth 1 -type d \
| sed 's_$_/bin_' \
| tr '\n' ':' \
| sed 's/:$//'
)
export PATH="$bins:$PATH"
Produces:
/home/user/apps/foo/bin:/home/user/apps/bar/bin:/home/user/apps/blah/bin:...
There's possibly a ridiculously negligible performance hit since command lookups will briefly try to look in directories that don't exist, and it feels bad adding non-existing directories to my $PATH
, but convenience-wise this is my preferred option.
2. Use stow
to generate symlinks to your executables
stow
was created for exactly this purpose. I'm currently using this setup to store all of my dotfiles in a git repo and copy them to my home directory :)
If you have a directory structure like:
.
├── bar
│ └── bin
│ ├── bar-executable-1
│ └── bar-executable-2
├── bin
└── foo
└── bin
├── foo-executable-1
└── foo-executable-2
And you want all of the files in bar/bin/* and foo/bin/* to be linked to in bin/, you can run:
cd somedir
stow -v --restow --target bin/ --dir bar/ bin
stow -v --restow --target bin/ --dir foo/ bin
note: I use --restow
for pruning, as it'll delete any old symlinks first before re-creating new symlinks
This generates:
somedir
├── bar
│ └── bin
│ ├── bar-executable-1
│ └── bar-executable-2
├── bin
│ ├── bar-executable-1 -> ../bar/bin/bar-executable-1
│ ├── bar-executable-2 -> ../bar/bin/bar-executable-2
│ ├── foo-executable-1 -> ../foo/bin/foo-executable-1
│ └── foo-executable-2 -> ../foo/bin/foo-executable-2
└── foo
└── bin
├── foo-executable-1
└── foo-executable-2
And then you can simply add somedir/bin/ to your PATH
making stow
a little easier to use
If
- The only directory inside each appN directory is a single bin/ directory and
- You're okay with moving the compiled bin/ directory outside of your apps/ directory
then you can use a slightly easier stow
command:
/home/user
├── Desktop
├── Documents
├── Pictures
├── Videos
├── apps
│ ├── bar
│ │ └── bin
│ │ ├── bar-executable-1
│ │ └── bar-executable-2
│ └── foo
│ └── bin
│ ├── foo-executable-1
│ └── foo-executable-2
└── bin
cd
stow -v --restow --target ./ --dir apps/ foo bar
This basically says Look in the "apps" folder for "packages" named "foo" and "bar", and copy the entire contents of both of those packages to the current directory using symlinks. So if all that you have in apps/foo/ and apps/bar/ is a single bin/ folder, then this generates a single bin/ folder in the current directory with links to all of the files in apps/foo/bin/ and apps/bar/bin/.
If, however, you have lots of other files/folders in apps/foo/ and apps/bar/ besides just a single bin/ directory, then it'll recreate all of those in your home folder as well, which is probably not desirable, and you should stick with the first stow
example.
https://www.gnu.org/software/stow/manual/html_node/Installing-Packages.html
/home/user/apps/all-apps/
directory and just add that one directory?