First, create a suitable directory structure:
# your desired namespace
mkdir -p -- "$HOME"/.namespaces/wasi-sdk
# some testing namespaces
mkdir -p -- "$HOME"/.namespaces/bar "$HOME"/.namespaces/baz "$HOME"/.namespaces/surprise
Populate the directories:
# your desired utility
ln -s -- /usr/bin/wasi-sdk/clang "$HOME"/.namespaces/wasi-sdk/clang
# some testing utilities
ln -s -- /usr/bin/date "$HOME"/.namespaces/bar/foo
ln -s -- /usr/bin/echo "$HOME"/.namespaces/baz/foo
ln -s -- /usr/bin/date "$HOME"/.namespaces/surprise/ls
ln -s -- /usr/bin/ls "$HOME"/.namespaces/surprise/date
ln -s -- /usr/bin/ls "$HOME"/.namespaces/surprise/foo
Create more symlinks:
( cd -- "$HOME"/.namespaces \
&& find . ! -type d -path './*/*' -exec sh -c '
for f do
n="$(printf "%s\\n" "$f" | sed "s|/|.|g; s|^\\.\\.|./|")"
ln -s -- "$f" "$n"
done
' find-sh {} +
)
Do not worry if you don't understand the above code; in the future you may as well create and manage symlinks manually. This is how the directory structure looks now:
$ ( cd -- "$HOME"/.namespaces && tree )
.
├── bar
│ └── foo -> /usr/bin/date
├── bar.foo -> ./bar/foo
├── baz
│ └── foo -> /usr/bin/echo
├── baz.foo -> ./baz/foo
├── surprise
│ ├── date -> /usr/bin/ls
│ ├── foo -> /usr/bin/ls
│ └── ls -> /usr/bin/date
├── surprise.date -> ./surprise/date
├── surprise.foo -> ./surprise/foo
├── surprise.ls -> ./surprise/ls
├── wasi-sdk
│ └── clang -> /usr/bin/wasi-sdk/clang
└── wasi-sdk.clang -> ./wasi-sdk/clang
5 directories, 12 files
So in the "namespace" directories there are symlinks to real utilities. Additionally in the "main" directory there are symlinks (named namespace.name) to those symlinks.
Add the "main" directory to your $PATH:
PATH="$HOME/.namespaces:$PATH"
Now bar.foo is date and baz.foo is echo (try baz.foo Hello World). More importantly wasi-sdk.clang should work for you.
To be able to use use wasi-sdk as you wish, define a function that will manipulate your $PATH:
use () {
PATH="$(
dir="$HOME"/.namespaces
oldpath="$PATH"
newpath="$dir"
for namespace do
entry="$dir/$namespace"
if [ -d "$entry" ]; then
newpath="$newpath:$entry"
else
printf 'Namespace %s not found.\n' "$namespace" >&2
fi
done
while [ -n "$oldpath" ]; do
IFS=: read -r entry oldpath <<EOF
$oldpath
EOF
case "$entry" in
"$dir"/* | "$dir")
entry=''
;;
*)
entry=":$entry"
;;
esac
newpath="$newpath$entry"
done
printf '%s' "$newpath"
)"
}
Now you can run use wasi-sdk and it will do what you want. You can run use surprise to "swap" date and ls (note this ls will fail if there is an alias like alias ls='ls --color=auto'), and to make foo behave like ls. Better, you can run use bar surprise to "swap" date and ls (like in surprise), and to make foo behave like date (like in bar, overriding surprise).
In general use namespace1 namespace2 namespace3 ... allows you to use multiple namespaces (namespace1 has the highest priority). The function is quite dumb (e.g. it will not deduplicate the list, it will happily accept ../../..).
To stop using namespaces this way, run use without arguments. Note it will still add the "main" directory to the path, even if it wasn't there before. This is deliberate, so you can choose not to change your $PATH account-wide and "activate" the support for this namespace.name syntax only on demand by invoking use (with or without arguments) for the first time.
Note that in general a program may adjust its behavior according to the name used to call it (example). Running such a program via a symlink named namespace.name may break things.