• Stars
    star
    1,744
  • Rank 26,695 (Top 0.6 %)
  • Language
    Shell
  • License
    MIT License
  • Created about 12 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

a delicious way to organize programs

sub: a delicious way to organize programs

Sub is a model for setting up shell programs that use subcommands, like git or rbenv using bash. Making a sub does not require you to write shell scripts in bash, you can write subcommands in any scripting language you prefer.

A sub program is run at the command line using this style:

$ [name of program] [subcommand] [(args)]

Here's some quick examples:

$ rbenv                    # prints out usage and subcommands
$ rbenv versions           # runs the "versions" subcommand
$ rbenv shell 1.9.3-p194   # runs the "shell" subcommand, passing "1.9.3-p194" as an argument

Each subcommand maps to a separate, standalone executable program. Sub programs are laid out like so:

.
├── bin               # contains the main executable for your program
├── completions       # (optional) bash/zsh completions
├── libexec           # where the subcommand executables are
└── share             # static data storage

Subcommands

Each subcommand executable does not necessarily need to be in bash. It can be any program, shell script, or even a symlink. It just needs to run.

Here's an example of adding a new subcommand. Let's say your sub is named rush. Run:

touch libexec/rush-who
chmod a+x libexec/rush-who

Now open up your editor, and dump in:

#!/usr/bin/env bash
set -e

who

Of course, this is a simple example... but now rush who should work!

$ rush who
qrush     console  Sep 14 17:15 

You can run any executable in the libexec directly, as long as it follows the NAME-SUBCOMMAND convention. Try out a Ruby script or your favorite language!

What's on your sub

You get a few commands that come with your sub:

  • commands: Prints out every subcommand available.
  • completions: Helps kick off subcommand autocompletion.
  • help: Document how to use each subcommand.
  • init: Shows how to load your sub with autocompletions, based on your shell.
  • shell: Helps with calling subcommands that might be named the same as builtin/executables.

If you ever need to reference files inside of your sub's installation, say to access a file in the share directory, your sub exposes the directory path in the environment, based on your sub name. For a sub named rush, the variable name will be _RUSH_ROOT.

Here's an example subcommand you could drop into your libexec directory to show this in action: (make sure to correct the name!)

#!/usr/bin/env bash
set -e

echo $_RUSH_ROOT

You can also use this environment variable to call other commands inside of your libexec directly. Composition of this type very much encourages reuse of small scripts, and keeps scripts doing one thing simply.

Self-documenting subcommands

Each subcommand can opt into self-documentation, which allows the subcommand to provide information when sub and sub help [SUBCOMMAND] is run.

This is all done by adding a few magic comments. Here's an example from rush who (also see sub commands for another example):

#!/usr/bin/env bash
# Usage: sub who
# Summary: Check who's logged in
# Help: This will print out when you run `sub help who`.
# You can have multiple lines even!
#
#    Show off an example indented
#
# And maybe start off another one?

set -e

who

Now, when you run sub, the "Summary" magic comment will now show up:

usage: sub <command> [<args>]

Some useful sub commands are:
   commands               List all sub commands
   who                    Check who's logged in

And running sub help who will show the "Usage" magic comment, and then the "Help" comment block:

Usage: sub who

This will print out when you run `sub help who`.
You can have multiple lines even!

   Show off an example indented

And maybe start off another one?

That's not all you get by convention with sub...

Autocompletion

Your sub loves autocompletion. It's the mustard, mayo, or whatever topping you'd like that day for your commands. Just like real toppings, you have to opt into them! Sub provides two kinds of autocompletion:

  1. Automatic autocompletion to find subcommands (What can this sub do?)
  2. Opt-in autocompletion of potential arguments for your subcommands (What can this subcommand do?)

Opting into autocompletion of subcommands requires that you add a magic comment of (make sure to replace with your sub's name!):

# Provide YOUR_SUB_NAME completions

and then your script must support parsing of a flag: --complete. Here's an example from rbenv, namely rbenv whence:

#!/usr/bin/env bash
set -e
[ -n "$RBENV_DEBUG" ] && set -x

# Provide rbenv completions
if [ "$1" = "--complete" ]; then
  echo --path
  exec rbenv shims --short
fi

# lots more bash...

Passing the --complete flag to this subcommand short circuits the real command, and then runs another subcommand instead. The output from your subcommand's --complete run is sent to your shell's autocompletion handler for you, and you don't ever have to once worry about how any of that works!

Run the init subcommand after you've prepared your sub to get your sub loading automatically in your shell.

Shortcuts

Creating shortcuts for commands is easy, just symlink the shorter version you'd like to run inside of your libexec directory.

Let's say we want to shorten up our rush who to rush w. Just make a symlink!

cd libexec
ln -s rush-who rush-w

Now, rush w should run libexec/rush-who, and save you mere milliseconds of typing every day!

Prepare your sub

Clone this repo:

git clone [email protected]:qrush/sub.git [name of your sub]
cd [name of your sub]
./prepare.sh [name of your sub]

The prepare script will run you through the steps for making your own sub. Also, don't call it sub, by the way! Give it a better name.

Install your sub

So you've prepared your own sub, now how do you use it? Here's one way you could install your sub in your $HOME directory:

cd
git clone [YOUR GIT HOST URL]/sub.git .sub

For bash users:

echo 'eval "$($HOME/.sub/bin/sub init -)"' >> ~/.bash_profile
exec bash

For zsh users:

echo 'eval "$($HOME/.sub/bin/sub init -)"' >> ~/.zshenv
source ~/.zshenv

You could also install your sub in a different directory, say /usr/local. This is just one way you could provide a way to install your sub.

License

MIT. See LICENSE.

More Repositories

1

unix

Mirror of the Restoration of 1st Edition UNIX kernel sources from pdf document.
C
791
star
2

m

A Test::Unit runner that can run tests by line number.
Ruby
377
star
3

motion-layout

A nice way to use iOS6+ autolayout in your RubyMotion app. Use ASCII-art inspired format strings to build your app's layout!
Ruby
215
star
4

hola

example gem repo
Ruby
124
star
5

motion-settings-bundle

Create a Settings.bundle for your RubyMotion app
Ruby
110
star
6

gitready

learn git one commit at a time. updates weekly or when great tips are found
98
star
7

vim-fu

Combining the awesomeness of various vim plugins in one easy configurable unit.
Vim Script
38
star
8

shp

A new UI for git. This doesn't work yet.
Rust
28
star
9

pubsub

easy example of redis pubsub
Ruby
27
star
10

qrush.github.com

coding with spice
CSS
26
star
11

skyway

Official news, tour, stats and community site for Aqueous
Ruby
22
star
12

rebase

A weekly update about GitHub!
Ruby
15
star
13

react-native-wkwebview

WKWebView for React Native (+ a few nice things)
Objective-C
12
star
14

snake

A simple Snake game, written in Shoes.
Ruby
9
star
15

danger_danger

example rails 3.1.1 app using high_voltage for a static site
Ruby
9
star
16

gsay

SPEAK LIKE A GOOGLE ROBOT
Ruby
9
star
17

mon

A pokemon battle simulator
Ruby
7
star
18

kidsmash-mac

Kidsmash: 🍎
Swift
6
star
19

beardo

Co-ops are run by dirty hippies; dirty hippies have beards; therefore, this app is called beardo.
5
star
20

higo

go, on heroku!
Ruby
5
star
21

kidsmash

KID SMASH - JavaScript port of BabySmash for SE444
JavaScript
5
star
22

beesknees

a boggle clone && an experiment with redis
Ruby
4
star
23

dfat

DWARF FORTRESS ADVENTURE TIME
Ruby
4
star
24

gemwhisperer

THE GEM WHISPERER: HE SPEAKS TO GEMS
JavaScript
3
star
25

go

explorations into google's go
Go
3
star
26

archive

My twitter archive
JavaScript
3
star
27

nyruby

nyruby: the empire state's ruby group
Ruby
3
star
28

LookInside

An actual compiling sample code repo from WWDC 2014: A Look Inside Presentation Controllers
Objective-C
3
star
29

test-without-issues

2
star
30

wedding

JavaScript
2
star
31

mwnbot

Java
2
star
32

counter

a carcassonne counter
Ruby
2
star
33

df

dorf fortress.
2
star
34

ThreadMessages

Ruby
2
star
35

mwrc

sandbox/playground for my MWRC 2011 talk
Ruby
2
star
36

q-tracer

c# raytracer project for cg2
C#
1
star
37

arel-test

Ruby
1
star
38

gifs

CSS
1
star
39

ec2bootstrapper

git-svn clone of the C# EC2 bootstrapper from CodePlex
C#
1
star
40

q

Shell
1
star
41

nathanlanevsraptor

a tweetstream demo, made during BarCampBoston 6
JavaScript
1
star
42

historian-extension

1
star
43

aftest

Ruby
1
star
44

q-blizzard

another CG2 project, this time a c# particle system
C#
1
star
45

notvirus.news

CSS
1
star
46

cheeseburger

redis: data cheeseburgers!
Ruby
1
star
47

stupidrubytricks

WNYRuby December 2011 Talk
Ruby
1
star