shell dot on steroids https://pagure.io/shellfu
Alois Mahdal 71594db940 Update meta-data with newer, more accurate tagline 6 years ago
notes Remove obsolete project notes 7 years ago
packaging Make better use of meta-data from mkit.ini 6 years ago
src Fix function exporting bug 7 years ago
tests Add test for special chars in section/key/value 7 years ago
utils Update TFKit to v0.0.14 6 years ago
.gitignore Update .gitignore for new TFKit 8 years ago
LICENSE.md Use Markdown version of LICENSE file 6 years ago
Makefile Update meta-data with newer, more accurate tagline 6 years ago
README.md Add a (somehow) useful README 7 years ago
mkit.ini Update meta-data with newer, more accurate tagline 6 years ago

README.md

Shellfu

Shellfu - shell dot on steroids

Disclaimer: Use at your own risk. See Project Status below for details.

Project Status and Versioning

  • Development stage is something between "experimental" and "alpha", that is lot of tests are yet to be written and only real user is its own author.

  • API (commands, options...) may be changed/removed as needed.

  • Although that will not happen within same version.

  • Branch 'last' contains only the last released version. Changes in this branch can be API-breaking.

  • Branch 'devel' is generally treated as development version and opposed to 'last', is more likely to contain bugs.

  • Branch 'master' is used only for pre-release merging; don't build your work on it.

Introduction

Most shell languages don't have libraries.

You might think: "Are you kidding me? Libraries are for real serious programmers, and real serious programmers don't real-serious-program in shell! So how is that a problem lol."

I mostly agree. Shell languages, by definition are command languages, basically meant to allow you kick around files, create directories and most importantly, launch other real serious programs.

What shell languages can also be used for is gluing together some of these real serious programs so that you don't have to type everything over and over. These glue scripts are normally nothing serious, just copy this there and launch that with that piped in. Done.

Granted, in some cases, you simply don't stop there. Sometimes you create one script here, one script there, one over there. When you maintain a system, sometimes you do write scripties here and there. That's OK, all of them are just few lines; trivial things with obvious purpose, right?

But sometimes, you don't work alone. Sometimes there's bunch of other folks and you want to work together so that when you take vacation and something breaks, your colleagues can use your scripts instead of needing to do everything manually or call you.

So even if it's not real serious web application or real serious kernel, some level of re-usability pays off.

OK so what

It's not that it's not possible to build a library from a bunch of scripts and import all with the magical dot command, but let's be honest: you end up either with swarm of modules of varying style, maturity and quality and overlapping scopes, or one humongous beast-of-a-module with pack of mysterious functions and variables that everyone is scared to touch.

Unless you take it seriously and start thinking way ahead from the start.

Which is exactly what I did.

Finding myself in swarm of varying scripties, constantly trying to keep them at least a bit tidy, I decided to stop and do it another way: Just try and see how much of the magic, the modularity, maintainability and discoverability that's so common in other platforms could be taken into the dark, blunt world of shell languages.

Result of these efforts is called Shellfu.

So what does it do?

Shellfu, as a project consists of three parts:

  • shellfu(), the shell function that lets you import a module from known location just by name, therefore decoupling the deployment from the dependency.

  • Shellfu core library, providing few modules readily usable for some of the most common tasks (printing messages for user, loading basic INI files...).

    Note that this "library" is currently extremely tiny with about 4-6 modules. It's currently (July 2016) not clear what modules should be added or removed and what should be the size, although there are no plans to add a lot. Most of advantage of shellfu is to be gained from writing domain-specific modules.

  • Shellfu Style Guide, setting common standard for shell modules, allowing you to collaborate on the code in an efficient manner (in-line documentation, peer review, code readability...).

  • As a bonus, shellfu-doc, building upon the Shellfu Style Guide, allows your user to discover and read documentation of installed modules (akin to perldoc or pydoc).

Schizophrenia kicks in

So are we talking POSIX shell, Bash or Zsh or what?

The basic principle is, albeit untested, meant to be extensible to most common bourne-like shell languages. In more specific sense, this means two things:

  • shellfu.sh, the core part of the code should be compatible with dash, the Debian Almquist Shell,

  • although I don't expect various-language modules to co-exist, shellfu.sh aims to be able to filter modules based on interpreter (more on that later).

  • and some modules of the core library will try to be POSIX/dash compatible, which will make them loadable from all.

Note that I'm kind of using terms "POSIX" and "dash" interchangeably. What I really mean is that since POSIX is rather vague in many places, and there are kajilions of POSIX shells, it's impractical to aim for real POSIX compatibility. Therefore, the "POSIX-oriented" code will be tested under dash, plus set of most common interpreters: bash, (add here).

I reckon that's about as POSIXey as one can get without going mad.

Bring it on!

Installation

OK, less talk, more make. Dependencies are almost none: you'll need just bash and common Linux utilities. So basically, none.

git clone <insert-url-here>
cd shellfu
make
sudo make install

You can also run our humble test suite (~10 seconds):

make test

Alternatively you can ask author for highly non-standard but working RPM/DEB packages; availability is currently on-demand-happily.

Your first script

After installing, one of the first things you can do is:

shellfu-get path
shellfu-get --version

That should return path to shellfu.sh and version, respectively. And that's also all this command does.

Next, if you have also installed some modules, you can look around using shellfu-doc:

shellfu-doc --lsmods
shellfu-doc inigrep

This is how you access documentation of modules available on the system. You can also access documentation of a modules directly by specifying path to the file (the path must contain slash):

shellfu-doc path/to/my/module.sh

Note that shellfu-doc only works if the module follows Shellfu Style Guide, in particular the Docstrings section.

Next, you can create your first Shellfu-Bash script:

#!/usr/bin/bash

. "$(shellfu-get path)" || exit 3

shellfu import pretty

think "this will be displayed if PRETTY_VERBOSE is 'true'"
debug "this will be displayed if PRETTY_DEBUG is 'true'"

fn() {
    local some_var=some value
    local some_array=(some items)
    debug -v some_var some_array something_else
}

warn "I'm getting tired"

fn

die "ok I'm done"

This is how above script works:

  1. shellfu-get provides path to the main shellfu.sh, which defines shellfu() function (plus a bunch of boring variables).

  2. Using shellfu import pretty, we're importing module called "pretty". shellfu will figure out where exactly it is.

  3. If we called shellfu-doc pretty in another terminal, we would find out that among others, this module contains functions think, debug, warn and die.

  4. Rest of it is just showing off how cool pretty is.

Calling the script is the same as any other bash scripts, what you can do though, is play with some pretty variables:

PRETTY_DEBUG=true ./my_script
PRETTY_VERBOSE=true ./my_script
PRETTY=color PRETTY_DEBUG=true ./my_script
PRETTY=notify PRETTY_VERBOSE=true ./my_script

Your first module

In its most basic form, a Shellfu module is nothing special. All you need to do is

  1. write a file with .sh extension with some bash functions/variables,

  2. save it somewhere,

  3. in your script, call shellfu import my_module--you can now access the functions/variables you have defined.

  4. When running your script, set SHELLFU_PATH to the location where my_module.sh is.

To get the basic stuff, nothing more is really needed. If you want, however, your module be explorable by shellfu-doc, you need to follow Shellfu Style Guide.

And friends

Apart from Shellfu, there also other "sibling" projects helping you even furhter:

  • TFkit -- to help create and run unit test suites for shell functions and commands.

  • MKit -- to help get you started with boring stuff like deployment, packaging (deb and rpm) and release management (versioning, changelogs).

  • saturnin -- to help with creating more rich toolkits in form of meta-commands.

Not all of them are public, yet (but all of them will be). Well, the first two are actually integrated in, and used to maintain Shellfu codebase.

Contact

Author of Shellfu idea, design and code is Alois Mahdal .

For general questions, visit #shellfu at freenode.

More communication channels will be added at some point.