subcom – tool to manage subcommands of your executable.

Synopsis

subcom [-a |-w |-s] [-p path] [-d |-n] script arguments
subcom --help|--version

Description

subcom is the tool to determine subcommands from arguments of your executable file.

Subcommand is an executable file, found at locations, relative to the main script. The main script is first non-option argument of subcom. The name of subcommand and main script must consist of letters of latin alphabet (a-z, A-Z), digits, underscore symbol (_) or dash symbol (-). Names cannot start with dash symbol.

For example, you have script foo and its subcommand bar, located at foo-bar. The invocation of

    $ subcom foo bar
will print absolute path of foo-bar executable file: /usr/bin/foo-bar

Remaining command line arguments, which do not represent subcommand, will be omitted:

    $ subcom foo bar la la hey 1 2 3
The result will be:
    /usr/bin/foo-bar
You may list remaining arguments with -a option, see it below.

Locations

There are several types of locations to search for subcommands. subcom checks paths by two schemes: dash-delimeted words and nested directories.

Dash-delimited files are checked in two locations as follows.

One location is the directory with executable file.
foo bar
/usr/bin/foo-bar
foo bar more
/usr/bin/foo-bar-more
/usr/local/bin/foo bar
/usr/local/bin/foo-bar
Example above demonstrates search in the same directory, which contains original foo.

Another location is in the directory ../lib/foo/, relative to original executable foo.
foo bar
/usr/lib/foo/foo-bar
foo bar more
/usr/lib/foo/foo-bar-more
/usr/local/bin/foo bar
/usr/local/lib/foo/foo-bar

Nested directories are checked like this:

foo bar
/usr/bin/foo and /usr/libexec/foo/bar
foo bar more
/usr/bin/foo and /usr/libexec/foo/bar/more
/usr/local/bin/foo bar
/usr/local/libexec/foo/bar
In the example above the location of subcommands /usr/libexec/foo/ is calculated relatively to the location of main executable /usr/bin/foo. The same scheme keeps working with another prefixes instead of /usr above, like /usr/local or any other.

The scheme with nested subdirectories has specific case for the launch:

subcom foo bar lala
When lala is not correct subcommand, but there is nested subdirectory bar, the following file will be checked up as matching subcommand as well:
/usr/libexec/foo/bar/bar

As shown above, the location of subcommands is bound to the location of executable script (first argument foo in examples above) by default. The location to search for subcommands can be changed with the option -p.

The scheme with dashes has higher priority over nested directories. If subcommand with dashes is found, contents of nested directories are ignored.

If no matching subcommands are found, or no correct main script is given, subcom prints nothing to output. So one may check, whether some subcommand was found:

test -n "$(subcom foo bar lala)"

Generic usage example

The generic scheme to use subcom in some launcher script may look like this:

command="$(subcom "$0" "$@")"
if test -z "${command}" ; then
    # handle the absence of subcommand
    exit
fi
for arg in $(subcom -s "$0" "$@") ; do
    shift
done

$command "$@"

The first string is used to get the possible executable name.

command="$(subcom "$0" "$@")"
$0 here holds the executable name of main launcher script. $@ contains the argument string.

The next block checks if some subcommand has been found.

if test -z "${command}" ; then
    # handle the absence of subcommand
    exit
fi
If subcom hasn't found an executable, matching anything in command string, it will be silent and command variable will be empty.

The next block gets rid off the arguments in the initial command string, which decode the subcommand. The information about subcommand is stored in variable command after the code above.

for arg in $(subcom -s "$0" "$@") ; do
    shift
done

Finally, we launch found subcommand with all remaining arguments:

$command "$@"

Options

Options -a, -w and -s are mutually exclusive. If given at the same time, only the most right one in cmd will take effect.

Options -d and -n are mutually exclusive too, as described above.

-a
Print all arguments, remaining after the found executable subcommand. Arguments will be printed by one at a string like this:
$ subcom foo bar la la hey
With the output:
/usr/bin/foo-bar
la
la
hey


That sort of output allows to handle correctly arguments with spaces inside:
$ subcom foo bar "la la" hey
According output:
/usr/bin/foo-bar
la la
hey

-w
Print only the remaining arguments after the executable subcommand has been found.

-s
Print only the arguments, according to found executable subcommand. The arguments are in one line and delimited with spaces.

The option is used to skip the arguments, which encode the subcommand, in a cycle. That can be done like this:
for arg in $(subcom -s fooname "$@") ; do
    shift
done
After that the command string in $@ will not contain anything about subcommand executable.

-p dir
Set directory dir as the path to search for subcommands.

For the script /usr/bin/foo and subcommand /usr/bin/foo-bar:
subcom -p /usr/bin foo bar
equals to default behaviour:
subcom foo bar


For the script /usr/bin/foo and subcommand /usr/libexec/foo/bar:
subcom -p /usr/libexec foo bar
equals to default behaviour:
subcom foo bar

-d
Use only scheme with dashes to search for subcommands: foo-bar-more.

-n
Use only scheme with nested subdirectories to search for subcommands: foo/bar/more.

--version
Print version and exit with 0 code.
--help
Print short help description and exit with 0 code.

Error codes

1
Generic error.
2
No executable was given in command string.
3
Given main file is not executable.
4
Explicitly given path is not available.

See also

which(1)