The rc shell's nice feature for subdirectory searching of $PATH

September 13, 2021

I've used Byron Rakitzis's Unix reimplementation of Tom Duff's rc Plan 9 shell for a long time (for a variety of reasons). One of the ways that rc is different from standard Unix shells is that it has an unusual and surprisingly convenient additional feature in how it handles searching your $PATH.

In most Unix shells, if you type 'fred/barney' as a command name to execute, it's immediately interpreted as a relative path. For example, if you do:

$ fred/barney --help

this is the same as './fred/barney' and your shell will try to run something with that relative file name. This behavior matches the interpretation of this command name as a file name, since all file names that don't start with '/' are relative names.

In rc, relative names that don't start with './' or '../' are instead searched for on your $PATH, as the obvious combination of subdirectory (or subdirectories) and executable. If you do:

; fred/barney --help

then rc searches through your $PATH for something with a fred subdirectory with a barney in it. For example, it might wind up running $HOME/bin/fred/barney. See also this short description of rc's behavior.

This simple sounding feature turns out to be surprisingly useful. One way of putting it is that it lets you create namespaces for commands (with subdirectories being the namespaces); another way is that it lets you have "subcommands" of "commands" (where the "commands" are subdirectories and the subcommands are programs or shell scripts in it). In the rc approach, you would not have a "git" command that had dozens of subcommands and type 'git <subcommand>'; instead you would have a 'git' subdirectory somewhere in your $PATH and type 'git/<subcommand>'.

(In a version of rc that has command completion that includes these subdirectories (see here and here), this also creates a natural and general mechanism for completion of these 'subcommands', since they are regular executables.)

As far as I know, this nice little feature isn't widely available in other Unix shells. It's supported in zsh through the PATH_DIRS option, although apparently command completion can be wonky. I don't think Bash implements this directly with some option, but you could probably use Bash's 'command not found' hook function to do a version of this (maybe without command completion).

(I was inspired to write this entry by reading sd: my script directory (via), which basically implements this for normal Unix shells by using a cover program.)

PS: In rc, your $PATH is really your $path. But rc synchronizes the two environment variables for you so I've simplified the situation in this entry.


Comments on this page:

As someone pointed out on the Unix Heritage Society's mailing list, recently:

What that doesn't give you is the ability to say "git <git-options> diff <git-diff-options>"…[1]

Having "main" or "global" command options on the one hand and sub-command options on the other does make good sense, though, if you ask me.

[1] https://minnie.tuhs.org/pipermail/tuhs/2021-August/024221.html

Written on 13 September 2021.
« Why I'm mostly not a fan of coloured text (in terminals or elsewhere)
There are (at least) two types of package managers »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Sep 13 23:57:04 2021
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.